mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 11:45:53 +01:00
Added support for Trekbuddy atlases
This commit is contained in:
parent
bd23120c2c
commit
bde3c8cc3d
@ -83,7 +83,8 @@ HEADERS += src/config.h \
|
||||
src/offlinemap.h \
|
||||
src/mapdir.h \
|
||||
src/matrix.h \
|
||||
src/tar.h
|
||||
src/tar.h \
|
||||
src/atlas.h
|
||||
SOURCES += src/main.cpp \
|
||||
src/gui.cpp \
|
||||
src/poi.cpp \
|
||||
@ -142,7 +143,8 @@ SOURCES += src/main.cpp \
|
||||
src/offlinemap.cpp \
|
||||
src/mapdir.cpp \
|
||||
src/matrix.cpp \
|
||||
src/tar.cpp
|
||||
src/tar.cpp \
|
||||
src/atlas.cpp
|
||||
RESOURCES += gpxsee.qrc
|
||||
TRANSLATIONS = lang/gpxsee_cs.ts \
|
||||
lang/gpxsee_sv.ts
|
||||
|
261
src/atlas.cpp
Normal file
261
src/atlas.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
#include <QDir>
|
||||
#include <QtAlgorithms>
|
||||
#include <QPainter>
|
||||
#include "tar.h"
|
||||
#include "atlas.h"
|
||||
|
||||
|
||||
#define ZOOM_THRESHOLD 0.9
|
||||
|
||||
#define TL(m) ((m)->xy2ll((m)->bounds().topLeft()))
|
||||
#define BR(m) ((m)->xy2ll((m)->bounds().bottomRight()))
|
||||
|
||||
static bool resCmp(const OfflineMap *m1, const OfflineMap *m2)
|
||||
{
|
||||
qreal r1, r2;
|
||||
|
||||
r1 = m1->resolution(m1->bounds().center());
|
||||
r2 = m2->resolution(m2->bounds().center());
|
||||
|
||||
return r1 > r2;
|
||||
}
|
||||
|
||||
static bool lonCmp(const OfflineMap *m1, const OfflineMap *m2)
|
||||
{
|
||||
return TL(m1).lon() < TL(m2).lon();
|
||||
}
|
||||
|
||||
static bool latCmp(const OfflineMap *m1, const OfflineMap *m2)
|
||||
{
|
||||
return TL(m1).lat() > TL(m2).lat();
|
||||
}
|
||||
|
||||
bool Atlas::isAtlas(const QFileInfoList &files)
|
||||
{
|
||||
for (int i = 0; i < files.count(); i++) {
|
||||
const QString &fileName = files.at(i).fileName();
|
||||
if (fileName.endsWith(".tar")) {
|
||||
Tar tar;
|
||||
if (!tar.load(files.at(i).absoluteFilePath())) {
|
||||
qWarning("%s: %s: error loading tar file", qPrintable(_name),
|
||||
qPrintable(fileName));
|
||||
return false;
|
||||
}
|
||||
QStringList tarFiles = tar.files();
|
||||
for (int j = 0; j < tarFiles.size(); j++)
|
||||
if (tarFiles.at(j).endsWith(".tba"))
|
||||
return true;
|
||||
} else if (fileName.endsWith(".tba"))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Atlas::computeZooms()
|
||||
{
|
||||
qSort(_maps.begin(), _maps.end(), resCmp);
|
||||
|
||||
_zooms.append(QPair<int, int>(0, _maps.count() - 1));
|
||||
for (int i = 1; i < _maps.count(); i++) {
|
||||
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds().center());
|
||||
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds().center());
|
||||
if (cur < last * ZOOM_THRESHOLD) {
|
||||
_zooms.last().second = i-1;
|
||||
_zooms.append(QPair<int, int>(i, _maps.count() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Atlas::computeBounds()
|
||||
{
|
||||
QList<QPointF> offsets;
|
||||
|
||||
for (int i = 0; i < _maps.count(); i++)
|
||||
offsets.append(QPointF());
|
||||
|
||||
for (int z = 0; z < _zooms.count(); z++) {
|
||||
qreal w = 0, h = 0;
|
||||
|
||||
QList<OfflineMap*> m;
|
||||
for (int i = _zooms.at(z).first; i <= _zooms.at(z).second; i++)
|
||||
m.append(_maps.at(i));
|
||||
|
||||
qSort(m.begin(), m.end(), lonCmp);
|
||||
offsets[_maps.indexOf(m.first())].setX(w);
|
||||
for (int i = 1; i < m.size(); i++) {
|
||||
if (TL(m.at(i)).lon() > TL(m.at(i-1)).lon()) {
|
||||
w += m.at(i-1)->ll2xy(Coordinates(TL(m.at(i)).lon(),
|
||||
TL(m.at(i-1)).lat())).x() - m.at(i-1)->bounds().left();
|
||||
offsets[_maps.indexOf(m.at(i))].setX(round(w));
|
||||
}
|
||||
}
|
||||
|
||||
qSort(m.begin(), m.end(), latCmp);
|
||||
offsets[_maps.indexOf(m.first())].setY(h);
|
||||
for (int i = 1; i < m.size(); i++) {
|
||||
if (TL(m.at(i)).lat() < TL(m.at(i-1)).lat()) {
|
||||
h += m.at(i-1)->ll2xy(Coordinates(TL(m.at(i-1)).lon(),
|
||||
TL(m.at(i)).lat())).y() - m.at(i-1)->bounds().top();
|
||||
offsets[_maps.indexOf(m.at(i))].setY(round(h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _maps.count(); i++)
|
||||
_bounds.append(QPair<QRectF, QRectF>(QRectF(TL(_maps.at(i)).toPointF(),
|
||||
BR(_maps.at(i)).toPointF()), QRectF(offsets.at(i),
|
||||
_maps.at(i)->bounds().size())));
|
||||
}
|
||||
|
||||
Atlas::Atlas(const QString &path, QObject *parent) : Map(parent)
|
||||
{
|
||||
_valid = false;
|
||||
|
||||
QFileInfo fi(path);
|
||||
_name = fi.fileName();
|
||||
|
||||
QDir dir(path);
|
||||
QFileInfoList files = dir.entryInfoList(QDir::Files);
|
||||
if (!isAtlas(files))
|
||||
return;
|
||||
|
||||
QFileInfoList layers = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (int n = 0; n < layers.count(); n++) {
|
||||
QDir zdir(layers.at(n).absoluteFilePath());
|
||||
QFileInfoList maps = zdir.entryInfoList(QDir::Dirs
|
||||
| QDir::NoDotAndDotDot);
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
OfflineMap *map = new OfflineMap(maps.at(i).absoluteFilePath());
|
||||
if (map->isValid())
|
||||
_maps.append(map);
|
||||
}
|
||||
}
|
||||
if (_maps.isEmpty()) {
|
||||
qWarning("%s: No usable maps available", qPrintable(_name));
|
||||
return;
|
||||
}
|
||||
|
||||
computeZooms();
|
||||
computeBounds();
|
||||
|
||||
_zoom = 0;
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
QRectF Atlas::bounds() const
|
||||
{
|
||||
QSizeF s(0, 0);
|
||||
|
||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
|
||||
if (_bounds.at(i).second.right() > s.width())
|
||||
s.setWidth(_bounds.at(i).second.right());
|
||||
if (_bounds.at(i).second.bottom() > s.height())
|
||||
s.setHeight(_bounds.at(i).second.bottom());
|
||||
}
|
||||
|
||||
return QRectF(QPointF(0, 0), s);
|
||||
}
|
||||
|
||||
qreal Atlas::resolution(const QPointF &p) const
|
||||
{
|
||||
int idx = _zooms.at(_zoom).first;
|
||||
|
||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
|
||||
if (_bounds.at(i).second.contains(p)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _maps.at(idx)->resolution(p);
|
||||
}
|
||||
|
||||
qreal Atlas::zoom() const
|
||||
{
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal Atlas::zoomFit(const QSize &size, const QRectF &br)
|
||||
{
|
||||
_zoom = 0;
|
||||
|
||||
for (int z = 0; z < _zooms.count(); z++) {
|
||||
for (int i = _zooms.at(z).first; i <= _zooms.at(z).second; i++) {
|
||||
if (_bounds.at(i).first.contains(br.center()))
|
||||
continue;
|
||||
|
||||
QRect sbr = QRectF(_maps.at(i)->ll2xy(br.topLeft()),
|
||||
_maps.at(i)->ll2xy(br.bottomRight())).toRect().normalized();
|
||||
|
||||
if (sbr.size().width() > size.width()
|
||||
|| sbr.size().height() > size.height())
|
||||
return _zoom;
|
||||
|
||||
_zoom = z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal Atlas::zoomIn()
|
||||
{
|
||||
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal Atlas::zoomOut()
|
||||
{
|
||||
_zoom = qMax(_zoom - 1, 0);
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
QPointF Atlas::ll2xy(const Coordinates &c) const
|
||||
{
|
||||
int idx = _zooms.at(_zoom).first;
|
||||
|
||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
|
||||
if (_bounds.at(i).first.contains(c.lon(), c.lat())) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QPointF p = _maps.at(idx)->ll2xy(c);
|
||||
return p + _bounds.at(idx).second.topLeft();
|
||||
}
|
||||
|
||||
Coordinates Atlas::xy2ll(const QPointF &p) const
|
||||
{
|
||||
int idx = _zooms.at(_zoom).first;
|
||||
|
||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
|
||||
if (_bounds.at(i).second.contains(p)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QPointF p2 = p - _bounds.at(idx).second.topLeft();
|
||||
return _maps.at(idx)->xy2ll(p2);
|
||||
}
|
||||
|
||||
void Atlas::draw(QPainter *painter, const QRectF &rect)
|
||||
{
|
||||
painter->fillRect(rect, Qt::white);
|
||||
|
||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
|
||||
if (rect.intersects(_bounds.at(i).second)) {
|
||||
OfflineMap *map = _maps.at(i);
|
||||
QRectF ir = rect.intersected(_bounds.at(i).second);
|
||||
const QPointF offset = _bounds.at(i).second.topLeft();
|
||||
QRectF pr = QRectF(ir.topLeft() - offset, ir.size());
|
||||
|
||||
painter->translate(offset);
|
||||
map->draw(painter, pr);
|
||||
painter->translate(-offset);
|
||||
}
|
||||
}
|
||||
}
|
47
src/atlas.h
Normal file
47
src/atlas.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef ATLAS_H
|
||||
#define ATLAS_H
|
||||
|
||||
#include <QFileInfoList>
|
||||
#include "map.h"
|
||||
#include "offlinemap.h"
|
||||
|
||||
|
||||
class Atlas : public Map
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Atlas(const QString &path, QObject *parent = 0);
|
||||
|
||||
const QString &name() const {return _name;}
|
||||
|
||||
QRectF bounds() const;
|
||||
qreal resolution(const QPointF &p) const;
|
||||
|
||||
qreal zoom() const;
|
||||
qreal zoomFit(const QSize &size, const QRectF &br);
|
||||
qreal zoomIn();
|
||||
qreal zoomOut();
|
||||
|
||||
QPointF ll2xy(const Coordinates &c) const;
|
||||
Coordinates xy2ll(const QPointF &p) const;
|
||||
|
||||
void draw(QPainter *painter, const QRectF &rect);
|
||||
|
||||
bool isValid() {return _valid;}
|
||||
|
||||
private:
|
||||
bool isAtlas(const QFileInfoList &files);
|
||||
void computeZooms();
|
||||
void computeBounds();
|
||||
|
||||
QString _name;
|
||||
bool _valid;
|
||||
|
||||
QList<OfflineMap*> _maps;
|
||||
QVector<QPair<int, int> > _zooms;
|
||||
QVector<QPair<QRectF, QRectF> > _bounds;
|
||||
int _zoom;
|
||||
};
|
||||
|
||||
#endif // ATLAS_H
|
@ -32,6 +32,8 @@ public:
|
||||
QPointF toMercator() const;
|
||||
static Coordinates fromMercator(const QPointF &m);
|
||||
|
||||
QPointF toPointF() const {return QPointF(_lon, _lat);}
|
||||
|
||||
private:
|
||||
qreal _lat, _lon;
|
||||
};
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include <QDir>
|
||||
#include "mapdir.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include "atlas.h"
|
||||
#include "offlinemap.h"
|
||||
#include "mapdir.h"
|
||||
|
||||
QList<Map*> MapDir::load(const QString &path, QObject *parent)
|
||||
{
|
||||
@ -21,12 +20,21 @@ QList<Map*> MapDir::load(const QString &path, QObject *parent)
|
||||
QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
QFileInfo fileInfo = list.at(i);
|
||||
OfflineMap *map = new OfflineMap(fileInfo.absoluteFilePath(), parent);
|
||||
|
||||
Atlas *atlas = new Atlas(fileInfo.absoluteFilePath(), parent);
|
||||
if (atlas->isValid())
|
||||
maps.append(atlas);
|
||||
else {
|
||||
delete atlas;
|
||||
|
||||
OfflineMap *map = new OfflineMap(fileInfo.absoluteFilePath(),
|
||||
parent);
|
||||
if (map->isValid())
|
||||
maps.append(map);
|
||||
else
|
||||
delete map;
|
||||
}
|
||||
}
|
||||
|
||||
return maps;
|
||||
}
|
||||
|
@ -353,6 +353,7 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
|
||||
if (!QPixmapCache::find(key, &pixmap)) {
|
||||
QByteArray ba = _tar.file(tileName);
|
||||
pixmap = QPixmap::fromImage(QImage::fromData(ba));
|
||||
if (!pixmap.isNull())
|
||||
QPixmapCache::insert(key, pixmap);
|
||||
}
|
||||
} else
|
||||
|
@ -65,7 +65,8 @@ bool Tar::load(const QString &path)
|
||||
QByteArray Tar::file(const QString &name)
|
||||
{
|
||||
QMap<QString, Tar::Info>::const_iterator it = _index.find(name);
|
||||
Q_ASSERT(it != _index.end());
|
||||
if (it == _index.end())
|
||||
return QByteArray();
|
||||
|
||||
if (_file.seek(it.value().offset()))
|
||||
return _file.read(it.value().size());
|
||||
|
Loading…
Reference in New Issue
Block a user