1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/map/atlas.cpp

312 lines
6.8 KiB
C++
Raw Normal View History

2017-03-26 15:32:55 +02:00
#include <QDir>
#include <QtAlgorithms>
#include <QPainter>
2017-11-26 18:54:03 +01:00
#include "common/rectc.h"
#include "ozimap.h"
2017-03-26 15:32:55 +02:00
#include "tar.h"
#include "atlas.h"
#define ZOOM_THRESHOLD 0.9
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
2017-03-26 15:32:55 +02:00
static bool resCmp(OziMap *m1, OziMap *m2)
2017-03-26 15:32:55 +02:00
{
qreal r1, r2;
r1 = m1->resolution(m1->bounds());
r2 = m2->resolution(m2->bounds());
2017-03-26 15:32:55 +02:00
return r1 > r2;
}
static bool xCmp(OziMap *m1, OziMap *m2)
2017-03-26 15:32:55 +02:00
{
return TL(m1).x() < TL(m2).x();
2017-03-26 15:32:55 +02:00
}
static bool yCmp(OziMap *m1, OziMap *m2)
2017-03-26 15:32:55 +02:00
{
return TL(m1).y() > TL(m2).y();
2017-03-26 15:32:55 +02:00
}
void Atlas::computeZooms()
{
qSort(_maps.begin(), _maps.end(), resCmp);
_zooms.append(Zoom(0, _maps.count() - 1));
2017-03-26 15:32:55 +02:00
for (int i = 1; i < _maps.count(); i++) {
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds());
2017-03-26 15:32:55 +02:00
if (cur < last * ZOOM_THRESHOLD) {
_zooms.last().last = i-1;
_zooms.append(Zoom(i, _maps.count() - 1));
2017-03-26 15:32:55 +02:00
}
}
}
void Atlas::computeBounds()
{
2018-08-18 21:06:36 +02:00
QVector<QPointF> offsets(_maps.count());
2017-03-26 15:32:55 +02:00
for (int z = 0; z < _zooms.count(); z++) {
QList<OziMap*> m;
for (int i = _zooms.at(z).first; i <= _zooms.at(z).last; i++)
2017-03-26 15:32:55 +02:00
m.append(_maps.at(i));
2017-04-01 05:59:55 +02:00
qSort(m.begin(), m.end(), xCmp);
offsets[_maps.indexOf(m.first())].setX(0);
2017-03-26 15:32:55 +02:00
for (int i = 1; i < m.size(); i++) {
2018-08-18 21:06:36 +02:00
qreal w = m.first()->pp2xy(TL(m.at(i))).x();
2017-04-04 01:19:17 +02:00
offsets[_maps.indexOf(m.at(i))].setX(w);
2017-03-26 15:32:55 +02:00
}
2017-04-01 05:59:55 +02:00
qSort(m.begin(), m.end(), yCmp);
offsets[_maps.indexOf(m.first())].setY(0);
2017-03-26 15:32:55 +02:00
for (int i = 1; i < m.size(); i++) {
2018-08-18 21:06:36 +02:00
qreal h = m.first()->pp2xy(TL(m.at(i))).y();
2017-04-04 01:19:17 +02:00
offsets[_maps.indexOf(m.at(i))].setY(h);
2017-03-26 15:32:55 +02:00
}
}
2018-08-18 21:06:36 +02:00
_bounds = QVector<Bounds>(_maps.count());
2017-03-26 15:32:55 +02:00
for (int i = 0; i < _maps.count(); i++)
2018-08-18 21:06:36 +02:00
_bounds[i] = Bounds(RectD(TL(_maps.at(i)), BR(_maps.at(i))),
QRectF(offsets.at(i), _maps.at(i)->bounds().size()));
2017-03-26 15:32:55 +02:00
}
2018-03-09 18:56:54 +01:00
Atlas::Atlas(const QString &fileName, QObject *parent)
2020-12-02 23:58:11 +01:00
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _valid(false)
2017-03-26 15:32:55 +02:00
{
QFileInfo fi(fileName);
QByteArray ba;
QString suffix = fi.suffix().toLower();
2018-03-08 02:24:10 +01:00
Tar tar(fileName);
2017-04-04 22:03:42 +02:00
_name = fi.dir().dirName();
2017-03-26 15:32:55 +02:00
if (suffix == "tar") {
2018-03-08 02:24:10 +01:00
if (!tar.open()) {
_errorString = "Error reading tar file";
return;
}
QString tbaFileName = fi.completeBaseName() + ".tba";
ba = tar.file(tbaFileName);
} else if (suffix == "tba") {
QFile tbaFile(fileName);
if (!tbaFile.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening tba file: %1")
.arg(tbaFile.errorString());
return;
}
ba = tbaFile.readAll();
}
if (!ba.startsWith("Atlas 1.0")) {
_errorString = "Missing or invalid tba file";
2017-03-26 15:32:55 +02:00
return;
}
QDir dir(fi.absolutePath());
2017-03-26 15:32:55 +02:00
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++) {
QString mapFile = maps.at(i).absoluteFilePath() + "/"
+ maps.at(i).fileName() + ".map";
OziMap *map;
2017-04-04 22:03:42 +02:00
if (tar.isOpen())
map = new OziMap(mapFile, tar, this);
2017-03-27 02:41:30 +02:00
else
map = new OziMap(mapFile, this);
2017-03-26 15:32:55 +02:00
if (map->isValid())
_maps.append(map);
else {
_errorString = QString("Error loading map: %1: %2")
.arg(mapFile, map->errorString());
return;
}
2017-03-26 15:32:55 +02:00
}
}
if (_maps.isEmpty()) {
_errorString = "No maps found in atlas";
2017-03-26 15:32:55 +02:00
return;
}
computeZooms();
computeBounds();
_valid = true;
}
void Atlas::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
2018-08-18 21:06:36 +02:00
{
for (int i = 0; i < _maps.size(); i++)
_maps[i]->setDevicePixelRatio(deviceRatio, mapRatio);
2018-08-18 21:06:36 +02:00
computeBounds();
}
2018-07-13 09:51:41 +02:00
QRectF Atlas::bounds()
2017-03-26 15:32:55 +02:00
{
QSizeF s(0, 0);
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
if (_bounds.at(i).xy.right() > s.width())
s.setWidth(_bounds.at(i).xy.right());
if (_bounds.at(i).xy.bottom() > s.height())
s.setHeight(_bounds.at(i).xy.bottom());
2017-03-26 15:32:55 +02:00
}
return QRectF(QPointF(0, 0), s);
}
int Atlas::zoomFit(const QSize &size, const RectC &br)
2017-03-26 15:32:55 +02:00
{
_zoom = 0;
2018-03-09 18:56:54 +01:00
_mapIndex = -1;
2017-03-26 15:32:55 +02:00
2017-06-30 18:15:22 +02:00
if (!br.isValid()) {
_zoom = _zooms.size() - 1;
return _zoom;
}
2017-03-26 15:32:55 +02:00
for (int z = 0; z < _zooms.count(); z++) {
for (int i = _zooms.at(z).first; i <= _zooms.at(z).last; i++) {
if (!_bounds.at(i).pp.contains(_maps.at(i)->ll2pp(br.center())))
2017-03-26 15:32:55 +02:00
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;
}
2018-04-28 22:18:11 +02:00
void Atlas::setZoom(int zoom)
{
_mapIndex = -1;
_zoom = zoom;
}
int Atlas::zoomIn()
2017-03-26 15:32:55 +02:00
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
2018-03-09 18:56:54 +01:00
_mapIndex = -1;
2017-03-26 15:32:55 +02:00
return _zoom;
}
int Atlas::zoomOut()
2017-03-26 15:32:55 +02:00
{
_zoom = qMax(_zoom - 1, 0);
2018-03-09 18:56:54 +01:00
_mapIndex = -1;
2017-03-26 15:32:55 +02:00
return _zoom;
}
2017-04-30 00:19:53 +02:00
QPointF Atlas::ll2xy(const Coordinates &c)
2017-03-26 15:32:55 +02:00
{
PointD pp;
2017-03-26 15:32:55 +02:00
2018-03-09 18:56:54 +01:00
if (_mapIndex >= 0)
pp = _maps.at(_mapIndex)->ll2pp(c);
if (_mapIndex < 0 || !_bounds.at(_mapIndex).pp.contains(pp)) {
2018-03-09 18:56:54 +01:00
_mapIndex = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
pp = _maps.at(i)->ll2pp(c);
if (_bounds.at(i).pp.contains(pp)) {
2018-03-09 18:56:54 +01:00
_mapIndex = i;
2017-04-29 23:15:44 +02:00
break;
}
2017-03-26 15:32:55 +02:00
}
}
2018-03-09 18:56:54 +01:00
QPointF p = _maps.at(_mapIndex)->pp2xy(pp);
return p + _bounds.at(_mapIndex).xy.topLeft();
2017-03-26 15:32:55 +02:00
}
2017-04-30 00:19:53 +02:00
Coordinates Atlas::xy2ll(const QPointF &p)
2017-03-26 15:32:55 +02:00
{
int idx = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
if (_bounds.at(i).xy.contains(p)) {
2017-03-26 15:32:55 +02:00
idx = i;
break;
}
}
QPointF p2 = p - _bounds.at(idx).xy.topLeft();
2017-03-26 15:32:55 +02:00
return _maps.at(idx)->xy2ll(p2);
}
2018-08-23 20:26:10 +02:00
void Atlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
2017-03-26 15:32:55 +02:00
{
2017-04-01 05:59:55 +02:00
// All in one map
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
if (_bounds.at(i).xy.contains(rect)) {
2018-08-23 20:26:10 +02:00
draw(painter, rect, i, flags);
2017-04-01 05:59:55 +02:00
return;
}
}
2017-03-26 15:32:55 +02:00
2017-04-01 05:59:55 +02:00
// Multiple maps
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
QRectF ir = rect.intersected(_bounds.at(i).xy);
2017-04-01 05:59:55 +02:00
if (!ir.isNull())
2018-08-23 20:26:10 +02:00
draw(painter, ir, i, flags);
2017-04-01 05:59:55 +02:00
}
}
2017-03-26 15:32:55 +02:00
2018-08-23 20:26:10 +02:00
void Atlas::draw(QPainter *painter, const QRectF &rect, int mapIndex,
Flags flags)
2017-04-01 05:59:55 +02:00
{
OziMap *map = _maps.at(mapIndex);
const QPointF offset = _bounds.at(mapIndex).xy.topLeft();
2017-04-01 05:59:55 +02:00
QRectF pr = QRectF(rect.topLeft() - offset, rect.size());
2017-03-27 02:41:30 +02:00
2017-04-01 05:59:55 +02:00
map->load();
painter->translate(offset);
2018-08-23 20:26:10 +02:00
map->draw(painter, pr, flags);
2017-04-01 05:59:55 +02:00
painter->translate(-offset);
2017-03-26 15:32:55 +02:00
}
void Atlas::unload()
{
for (int i = 0; i < _maps.count(); i++)
_maps.at(i)->unload();
}
bool Atlas::isAtlas(const QString &path)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
if (suffix == "tar") {
2018-10-09 22:59:20 +02:00
Tar tar(path);
2018-03-08 02:24:10 +01:00
if (!tar.open())
return false;
QString tbaFileName = fi.completeBaseName() + ".tba";
return tar.contains(tbaFileName);
} else if (suffix == "tba")
return true;
return false;
}