mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 11:45:53 +01:00
Added support for OZF zoom levels
This commit is contained in:
parent
c708fa35fd
commit
73f06e61f0
@ -20,6 +20,7 @@
|
||||
#include "lambertconic.h"
|
||||
#include "albersequal.h"
|
||||
#include "ozf.h"
|
||||
#include "rectc.h"
|
||||
#include "offlinemap.h"
|
||||
|
||||
|
||||
@ -343,16 +344,19 @@ bool OfflineMap::getImageInfo(const QString &path)
|
||||
}
|
||||
|
||||
if (OZF::isOZF(_imgPath)) {
|
||||
_ozf.load(_imgPath);
|
||||
_size = _ozf.size();
|
||||
if (!_ozf.load(_imgPath)) {
|
||||
_errorString = QString("%1: Error loading OZF file")
|
||||
.arg(QFileInfo(_imgPath).fileName());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
QImageReader img(_imgPath);
|
||||
_size = img.size();
|
||||
}
|
||||
if (!_size.isValid()) {
|
||||
_errorString = QString("%1: Error reading map image")
|
||||
.arg(QFileInfo(_imgPath).fileName());
|
||||
return false;
|
||||
if (!_size.isValid()) {
|
||||
_errorString = QString("%1: Error reading map image")
|
||||
.arg(QFileInfo(_imgPath).fileName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -410,6 +414,8 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
|
||||
_img = 0;
|
||||
_projection = 0;
|
||||
_resolution = 0.0;
|
||||
_zoom = 0;
|
||||
_scale = QPointF(1.0, 1.0);
|
||||
|
||||
if (suffix == "tar") {
|
||||
if (!_tar.load(fileName)) {
|
||||
@ -476,6 +482,8 @@ OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
|
||||
_img = 0;
|
||||
_projection = 0;
|
||||
_resolution = 0.0;
|
||||
_zoom = 0;
|
||||
_scale = QPointF(1.0, 1.0);
|
||||
|
||||
QFileInfo map(fi.absolutePath());
|
||||
QFileInfo layer(map.absolutePath());
|
||||
@ -551,7 +559,7 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
|
||||
int x = tl.x() + i * _tileSize.width();
|
||||
int y = tl.y() + j * _tileSize.height();
|
||||
|
||||
if (!QRectF(QPointF(x, y), _ozf.tileSize()).intersects(bounds())) {
|
||||
if (!QRectF(QPointF(x, y), _tileSize).intersects(bounds())) {
|
||||
painter->fillRect(QRectF(QPoint(x, y), _tileSize), Qt::white);
|
||||
continue;
|
||||
}
|
||||
@ -594,22 +602,24 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
|
||||
int y = tl.y() + j * _ozf.tileSize().height();
|
||||
|
||||
if (!QRectF(QPointF(x, y), _ozf.tileSize()).intersects(bounds())) {
|
||||
painter->fillRect(QRectF(QPoint(x, y), _tileSize), Qt::white);
|
||||
painter->fillRect(QRectF(QPoint(x, y), _ozf.tileSize()),
|
||||
Qt::white);
|
||||
continue;
|
||||
}
|
||||
|
||||
QPixmap pixmap;
|
||||
QString key = _ozf.fileName() + "/" + QString::number(x)
|
||||
+ "_" + QString::number(y);
|
||||
QString key = _ozf.fileName() + "/" + QString::number(_zoom) + "_"
|
||||
+ QString::number(x) + "_" + QString::number(y);
|
||||
if (!QPixmapCache::find(key, &pixmap)) {
|
||||
pixmap = _ozf.tile(x, y);
|
||||
pixmap = _ozf.tile(_zoom, x, y);
|
||||
if (!pixmap.isNull())
|
||||
QPixmapCache::insert(key, pixmap);
|
||||
}
|
||||
|
||||
if (pixmap.isNull()) {
|
||||
qWarning("%s: error loading tile image", qPrintable(key));
|
||||
painter->fillRect(QRectF(QPoint(x, y), _tileSize), Qt::white);
|
||||
painter->fillRect(QRectF(QPoint(x, y), _ozf.tileSize()),
|
||||
Qt::white);
|
||||
} else
|
||||
painter->drawPixmap(QPoint(x, y), pixmap);
|
||||
}
|
||||
@ -636,3 +646,101 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
|
||||
else
|
||||
drawImage(painter, rect);
|
||||
}
|
||||
|
||||
QPointF OfflineMap::ll2xy(const Coordinates &c)
|
||||
{
|
||||
if (_ozf.isOpen()) {
|
||||
QPointF p(_transform.map(_projection->ll2xy(c)));
|
||||
return QPointF(p.x() * _scale.x(), p.y() * _scale.y());
|
||||
} else
|
||||
return _transform.map(_projection->ll2xy(c));
|
||||
}
|
||||
|
||||
Coordinates OfflineMap::xy2ll(const QPointF &p)
|
||||
{
|
||||
if (_ozf.isOpen()) {
|
||||
return _projection->xy2ll(_inverted.map(QPointF(p.x() / _scale.x(),
|
||||
p.y() / _scale.y())));
|
||||
} else
|
||||
return _projection->xy2ll(_inverted.map(p));
|
||||
}
|
||||
|
||||
QRectF OfflineMap::bounds() const
|
||||
{
|
||||
if (_ozf.isOpen())
|
||||
return QRectF(QPointF(0, 0), _ozf.size(_zoom));
|
||||
else
|
||||
return QRectF(QPointF(0, 0), _size);
|
||||
}
|
||||
|
||||
qreal OfflineMap::resolution(const QPointF &p) const
|
||||
{
|
||||
Q_UNUSED(p);
|
||||
|
||||
if (_ozf.isOpen())
|
||||
return _resolution / ((_scale.x() + _scale.y()) / 2.0);
|
||||
else
|
||||
return _resolution;
|
||||
}
|
||||
|
||||
qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
|
||||
{
|
||||
if (_ozf.isOpen()) {
|
||||
if (!br.isValid())
|
||||
rescale(0);
|
||||
else {
|
||||
QRect sbr(QRectF(_transform.map(_projection->ll2xy(br.topLeft())),
|
||||
_transform.map(_projection->ll2xy(br.bottomRight())))
|
||||
.toRect().normalized());
|
||||
|
||||
for (int i = 0; i < _ozf.zooms(); i++) {
|
||||
rescale(i);
|
||||
if (sbr.size().width() * _scale.x() <= size.width()
|
||||
&& sbr.size().height() * _scale.y() <= size.height())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal OfflineMap::zoomFit(qreal resolution, const Coordinates &c)
|
||||
{
|
||||
Q_UNUSED(c);
|
||||
|
||||
if (_ozf.isOpen()) {
|
||||
for (int i = 0; i < _ozf.zooms(); i++) {
|
||||
rescale(i);
|
||||
qreal sr = _resolution / ((_scale.x() + _scale.y()) / 2.0);
|
||||
if (sr >= resolution)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal OfflineMap::zoomIn()
|
||||
{
|
||||
if (_ozf.isOpen())
|
||||
rescale(qMax(_zoom - 1, 0));
|
||||
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
qreal OfflineMap::zoomOut()
|
||||
{
|
||||
if (_ozf.isOpen())
|
||||
rescale(qMin(_zoom + 1, _ozf.zooms() - 1));
|
||||
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
void OfflineMap::rescale(int zoom)
|
||||
{
|
||||
_zoom = zoom;
|
||||
_scale = QPointF(
|
||||
(qreal)_ozf.size(_zoom).width() / (qreal)_ozf.size(0).width(),
|
||||
(qreal)_ozf.size(_zoom).height() / (qreal)_ozf.size(0).height());
|
||||
}
|
||||
|
@ -23,19 +23,17 @@ public:
|
||||
|
||||
const QString &name() const {return _name;}
|
||||
|
||||
QRectF bounds() const {return QRectF(QPointF(0, 0), _size);}
|
||||
qreal resolution(const QPointF &) const {return _resolution;}
|
||||
QRectF bounds() const;
|
||||
qreal resolution(const QPointF &p) const;
|
||||
|
||||
qreal zoom() const {return 0;}
|
||||
qreal zoomFit(const QSize &, const RectC &) {return 0;}
|
||||
qreal zoomFit(qreal, const Coordinates &) {return 0;}
|
||||
qreal zoomIn() {return 0;}
|
||||
qreal zoomOut() {return 0;}
|
||||
qreal zoom() const {return _zoom;}
|
||||
qreal zoomFit(const QSize &size, const RectC &br);
|
||||
qreal zoomFit(qreal resolution, const Coordinates &c);
|
||||
qreal zoomIn();
|
||||
qreal zoomOut();
|
||||
|
||||
QPointF ll2xy(const Coordinates &c)
|
||||
{return _transform.map(_projection->ll2xy(c));}
|
||||
Coordinates xy2ll(const QPointF &p)
|
||||
{return _projection->xy2ll(_inverted.map(p));}
|
||||
QPointF ll2xy(const Coordinates &c);
|
||||
Coordinates xy2ll(const QPointF &p);
|
||||
|
||||
void draw(QPainter *painter, const QRectF &rect);
|
||||
|
||||
@ -86,6 +84,8 @@ private:
|
||||
void drawOZF(QPainter *painter, const QRectF &rect);
|
||||
void drawImage(QPainter *painter, const QRectF &rect);
|
||||
|
||||
void rescale(int zoom);
|
||||
|
||||
QString _name;
|
||||
bool _valid;
|
||||
QString _errorString;
|
||||
@ -102,6 +102,9 @@ private:
|
||||
QString _imgPath;
|
||||
QSize _tileSize;
|
||||
QString _tileName;
|
||||
|
||||
int _zoom;
|
||||
QPointF _scale;
|
||||
};
|
||||
|
||||
#endif // OFFLINEMAP_H
|
||||
|
147
src/ozf.cpp
147
src/ozf.cpp
@ -5,7 +5,6 @@
|
||||
|
||||
#define OZF2_MAGIC 0x7778
|
||||
#define OZF3_MAGIC 0x7780
|
||||
#define SEPARATOR 0x77777777
|
||||
|
||||
static const quint8 XKEY[] =
|
||||
{
|
||||
@ -39,21 +38,22 @@ template<class T> bool OZF::readValue(T &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OZF::read(void *data, size_t size)
|
||||
bool OZF::read(void *data, size_t size, size_t decryptSize)
|
||||
{
|
||||
if (_file.read((char*)data, size) < (qint64)size)
|
||||
return false;
|
||||
|
||||
if (_decrypt)
|
||||
decrypt(data, size, _key);
|
||||
decrypt(data, decryptSize ? qMin(decryptSize, size) : size, _key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OZF::readKey()
|
||||
bool OZF::initOZF3()
|
||||
{
|
||||
quint8 randomNumber, initial;
|
||||
quint32 keyblock;
|
||||
quint8 h1[8];
|
||||
|
||||
|
||||
if (!_file.seek(14))
|
||||
@ -66,7 +66,15 @@ bool OZF::readKey()
|
||||
if (!readValue(initial))
|
||||
return false;
|
||||
|
||||
_decrypt = true; _key = initial;
|
||||
_decrypt = true;
|
||||
_key = initial;
|
||||
|
||||
if (!_file.seek(0))
|
||||
return false;
|
||||
if (!read(h1, sizeof(h1)))
|
||||
return false;
|
||||
_tileSize = *(h1 + 6);
|
||||
|
||||
if (!_file.seek(15 + randomNumber))
|
||||
return false;
|
||||
if (!readValue(keyblock))
|
||||
@ -104,21 +112,28 @@ bool OZF::readKey()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OZF::initOZF2()
|
||||
{
|
||||
if (!_file.seek(6))
|
||||
return false;
|
||||
if (!readValue(_tileSize))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OZF::readHeaders()
|
||||
{
|
||||
quint16 magic;
|
||||
quint32 separator;
|
||||
|
||||
if (!readValue(magic))
|
||||
return false;
|
||||
|
||||
if (magic == OZF2_MAGIC) {
|
||||
if (!_file.seek(_file.pos() + 52))
|
||||
return false;
|
||||
if (!readValue(separator) || separator != SEPARATOR)
|
||||
if (!initOZF2())
|
||||
return false;
|
||||
} else if (magic == OZF3_MAGIC) {
|
||||
if (!readKey())
|
||||
if (!initOZF3())
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
@ -128,52 +143,58 @@ bool OZF::readHeaders()
|
||||
|
||||
bool OZF::readTileTable()
|
||||
{
|
||||
quint32 offset, bgr0, w, h;
|
||||
quint32 tableOffset, headerOffset, bgr0, w, h;
|
||||
quint16 x, y;
|
||||
int zooms;
|
||||
|
||||
|
||||
if (!_file.seek(_file.size() - sizeof(offset)))
|
||||
if (!_file.seek(_file.size() - sizeof(tableOffset)))
|
||||
return false;
|
||||
// table offset
|
||||
if (!readValue(offset))
|
||||
return false;
|
||||
if (!_file.seek(offset))
|
||||
return false;
|
||||
// tiles offset (zoom level 0)
|
||||
if (!readValue(offset))
|
||||
return false;
|
||||
if (!_file.seek(offset))
|
||||
if (!readValue(tableOffset))
|
||||
return false;
|
||||
zooms = (_file.size() - tableOffset - sizeof(quint32)) / sizeof(quint32);
|
||||
|
||||
if (!readValue(w))
|
||||
return false;
|
||||
if (!readValue(h))
|
||||
return false;
|
||||
if (!readValue(x))
|
||||
return false;
|
||||
if (!readValue(y))
|
||||
return false;
|
||||
|
||||
_size = QSize(w, h);
|
||||
_dim = QSize(x, y);
|
||||
|
||||
_palette = QVector<quint32>(256);
|
||||
if (!read(&(_palette[0]), sizeof(quint32) * 256))
|
||||
return false;
|
||||
for (int i = 0; i < _palette.size(); i++) {
|
||||
bgr0 = qFromLittleEndian(_palette.at(i));
|
||||
|
||||
quint32 b = (bgr0 & 0x000000FF);
|
||||
quint32 g = (bgr0 & 0x0000FF00) >> 8;
|
||||
quint32 r = (bgr0 & 0x00FF0000) >> 16;
|
||||
|
||||
_palette[i] = 0xFF000000 | r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
_tiles = QVector<quint32>(_dim.width() * _dim.height() + 1);
|
||||
for (int i = 0; i < _tiles.size(); i++)
|
||||
if (!readValue(_tiles[i]))
|
||||
for (int i = 0; i < zooms - 2; i++) {
|
||||
if (!_file.seek(tableOffset + i * sizeof(quint32)))
|
||||
return false;
|
||||
if (!readValue(headerOffset))
|
||||
return false;
|
||||
if (!_file.seek(headerOffset))
|
||||
return false;
|
||||
|
||||
if (!readValue(w))
|
||||
return false;
|
||||
if (!readValue(h))
|
||||
return false;
|
||||
if (!readValue(x))
|
||||
return false;
|
||||
if (!readValue(y))
|
||||
return false;
|
||||
|
||||
Zoom zoom;
|
||||
zoom.size = QSize(w, h);
|
||||
zoom.dim = QSize(x, y);
|
||||
|
||||
zoom.palette = QVector<quint32>(256);
|
||||
if (!read(&(zoom.palette[0]), sizeof(quint32) * 256))
|
||||
return false;
|
||||
for (int i = 0; i < zoom.palette.size(); i++) {
|
||||
bgr0 = qFromLittleEndian(zoom.palette.at(i));
|
||||
|
||||
quint32 b = (bgr0 & 0x000000FF);
|
||||
quint32 g = (bgr0 & 0x0000FF00) >> 8;
|
||||
quint32 r = (bgr0 & 0x00FF0000) >> 16;
|
||||
|
||||
zoom.palette[i] = 0xFF000000 | r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
zoom.tiles = QVector<quint32>(zoom.dim.width() * zoom.dim.height() + 1);
|
||||
for (int i = 0; i < zoom.tiles.size(); i++)
|
||||
if (!readValue(zoom.tiles[i]))
|
||||
return false;
|
||||
|
||||
_zooms.append(zoom);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -196,23 +217,25 @@ bool OZF::load(const QString &path)
|
||||
if (!readTileTable()) {
|
||||
qWarning("%s: file format error", qPrintable(_file.fileName()));
|
||||
_file.close();
|
||||
_size = QSize();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QPixmap OZF::tile(int x, int y)
|
||||
QPixmap OZF::tile(int zoom, int x, int y)
|
||||
{
|
||||
Q_ASSERT(_file.isOpen());
|
||||
Q_ASSERT(0 <= zoom && zoom < _zooms.count());
|
||||
|
||||
int i = (y/tileSize().height()) * _dim.width() + (x/tileSize().width());
|
||||
if (i >= _tiles.size() - 1 || i < 0)
|
||||
const Zoom &z = _zooms.at(zoom);
|
||||
|
||||
int i = (y/tileSize().height()) * z.dim.width() + (x/tileSize().width());
|
||||
if (i >= z.tiles.size() - 1 || i < 0)
|
||||
return QPixmap();
|
||||
|
||||
int size = _tiles.at(i+1) - _tiles.at(i);
|
||||
if (!_file.seek(_tiles.at(i)))
|
||||
int size = z.tiles.at(i+1) - z.tiles.at(i);
|
||||
if (!_file.seek(z.tiles.at(i)))
|
||||
return QPixmap();
|
||||
|
||||
quint32 bes = qToBigEndian(tileSize().width() * tileSize().height());
|
||||
@ -220,21 +243,27 @@ QPixmap OZF::tile(int x, int y)
|
||||
ba.resize(sizeof(bes) + size);
|
||||
*(ba.data()) = bes;
|
||||
|
||||
if (_file.read(ba.data() + sizeof(bes), size) != size)
|
||||
if (!read(ba.data() + sizeof(bes), size, 16))
|
||||
return QPixmap();
|
||||
if (_decrypt)
|
||||
decrypt(ba.data() + sizeof(bes), qMin(16, size), _key);
|
||||
QByteArray uba = qUncompress(ba);
|
||||
if (uba.size() != tileSize().width() * tileSize().height())
|
||||
return QPixmap();
|
||||
|
||||
QImage img((const uchar*)uba.constData(), tileSize().width(),
|
||||
tileSize().height(), QImage::Format_Indexed8);
|
||||
img.setColorTable(_palette);
|
||||
img.setColorTable(z.palette);
|
||||
|
||||
return QPixmap::fromImage(img.mirrored());
|
||||
}
|
||||
|
||||
QSize OZF::size(int zoom) const
|
||||
{
|
||||
Q_ASSERT(_file.isOpen());
|
||||
Q_ASSERT(0 <= zoom && zoom < _zooms.count());
|
||||
|
||||
return _zooms.at(zoom).size;
|
||||
}
|
||||
|
||||
bool OZF::isOZF(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
28
src/ozf.h
28
src/ozf.h
@ -4,6 +4,7 @@
|
||||
#include <QString>
|
||||
#include <QSize>
|
||||
#include <QColor>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QFile>
|
||||
#include <QPixmap>
|
||||
@ -18,27 +19,32 @@ public:
|
||||
QString fileName() const {return _file.fileName();}
|
||||
bool isOpen() const {return _file.isOpen();}
|
||||
|
||||
QSize size() const {return _size;}
|
||||
QSize tileSize() const {return QSize(64, 64);}
|
||||
QPixmap tile(int x, int y);
|
||||
int zooms() const {return _zooms.size();}
|
||||
QSize size(int zoom) const;
|
||||
QSize tileSize() const {return QSize(_tileSize, _tileSize);}
|
||||
QPixmap tile(int zoom, int x, int y);
|
||||
|
||||
static bool isOZF(const QString &path);
|
||||
|
||||
private:
|
||||
struct Zoom {
|
||||
QSize size;
|
||||
QSize dim;
|
||||
QVector<QRgb> palette;
|
||||
QVector<quint32> tiles;
|
||||
};
|
||||
|
||||
template<class T> bool readValue(T &val);
|
||||
bool read(void *data, size_t size);
|
||||
bool readKey();
|
||||
bool read(void *data, size_t size, size_t decryptSize = 0);
|
||||
bool initOZF3();
|
||||
bool initOZF2();
|
||||
bool readHeaders();
|
||||
bool readTileTable();
|
||||
|
||||
quint16 _tileSize;
|
||||
bool _decrypt;
|
||||
quint8 _key;
|
||||
|
||||
QSize _size;
|
||||
QSize _dim;
|
||||
QVector<QRgb> _palette;
|
||||
QVector<quint32> _tiles;
|
||||
|
||||
QList<Zoom> _zooms;
|
||||
QFile _file;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user