mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-27 21:24:47 +01:00
Added support for QCT maps
This commit is contained in:
parent
caae981c6a
commit
f63ee64f90
@ -146,6 +146,7 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/mapsforge/mapdata.h \
|
src/map/mapsforge/mapdata.h \
|
||||||
src/map/mapsforge/rastertile.h \
|
src/map/mapsforge/rastertile.h \
|
||||||
src/map/mapsforge/subfile.h \
|
src/map/mapsforge/subfile.h \
|
||||||
|
src/map/qctmap.h \
|
||||||
src/map/textpathitem.h \
|
src/map/textpathitem.h \
|
||||||
src/map/textpointitem.h \
|
src/map/textpointitem.h \
|
||||||
src/map/prjfile.h \
|
src/map/prjfile.h \
|
||||||
@ -339,6 +340,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/mapsforge/subfile.cpp \
|
src/map/mapsforge/subfile.cpp \
|
||||||
src/map/imgmap.cpp \
|
src/map/imgmap.cpp \
|
||||||
src/map/prjfile.cpp \
|
src/map/prjfile.cpp \
|
||||||
|
src/map/qctmap.cpp \
|
||||||
src/map/textpathitem.cpp \
|
src/map/textpathitem.cpp \
|
||||||
src/map/textpointitem.cpp \
|
src/map/textpointitem.cpp \
|
||||||
src/map/bsbmap.cpp \
|
src/map/bsbmap.cpp \
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "sqlitemap.h"
|
#include "sqlitemap.h"
|
||||||
#include "mapsforgemap.h"
|
#include "mapsforgemap.h"
|
||||||
#include "worldfilemap.h"
|
#include "worldfilemap.h"
|
||||||
|
#include "qctmap.h"
|
||||||
#include "invalidmap.h"
|
#include "invalidmap.h"
|
||||||
#include "maplist.h"
|
#include "maplist.h"
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ Map *MapList::loadFile(const QString &path, const Projection &proj, bool *isDir)
|
|||||||
else if (suffix == "wld" || suffix == "jgw" || suffix == "gfw"
|
else if (suffix == "wld" || suffix == "jgw" || suffix == "gfw"
|
||||||
|| suffix == "pgw" || suffix == "tfw")
|
|| suffix == "pgw" || suffix == "tfw")
|
||||||
map = new WorldFileMap(path, proj);
|
map = new WorldFileMap(path, proj);
|
||||||
|
else if (suffix == "qct")
|
||||||
|
map = new QCTMap(path);
|
||||||
|
|
||||||
return map ? map : new InvalidMap(path, "Unknown file format");
|
return map ? map : new InvalidMap(path, "Unknown file format");
|
||||||
}
|
}
|
||||||
@ -129,6 +132,7 @@ QString MapList::formats()
|
|||||||
+ qApp->translate("MapList", "Mapsforge maps") + " (*.map);;"
|
+ qApp->translate("MapList", "Mapsforge maps") + " (*.map);;"
|
||||||
+ qApp->translate("MapList", "OziExplorer maps") + " (*.map);;"
|
+ qApp->translate("MapList", "OziExplorer maps") + " (*.map);;"
|
||||||
+ qApp->translate("MapList", "MBTiles maps") + " (*.mbtiles);;"
|
+ qApp->translate("MapList", "MBTiles maps") + " (*.mbtiles);;"
|
||||||
|
+ qApp->translate("MapList", "QuickChart maps") + " (*.qct);;"
|
||||||
+ qApp->translate("MapList", "TwoNav maps") + " (*.rmap *.rtmap);;"
|
+ qApp->translate("MapList", "TwoNav maps") + " (*.rmap *.rtmap);;"
|
||||||
+ qApp->translate("MapList", "Locus/OsmAnd/RMaps SQLite maps")
|
+ qApp->translate("MapList", "Locus/OsmAnd/RMaps SQLite maps")
|
||||||
+ " (*.sqlitedb);;"
|
+ " (*.sqlitedb);;"
|
||||||
@ -144,7 +148,7 @@ QStringList MapList::filter()
|
|||||||
QStringList filter;
|
QStringList filter;
|
||||||
filter << "*.aqm" << "*.gfw" << "*.gmap" << "*.gmapi" << "*.img" << "*.jgw"
|
filter << "*.aqm" << "*.gfw" << "*.gmap" << "*.gmapi" << "*.img" << "*.jgw"
|
||||||
<< "*.jnx" << "*.kap" << "*.kmz" << "*.map" << "*.mbtiles" << "*.pgw"
|
<< "*.jnx" << "*.kap" << "*.kmz" << "*.map" << "*.mbtiles" << "*.pgw"
|
||||||
<< "*.rmap" << "*.rtmap" << "*.sqlitedb" << "*.tar" << "*.tba" << "*.tfw"
|
<< "*.qct" << "*.rmap" << "*.rtmap" << "*.sqlitedb" << "*.tar" << "*.tba"
|
||||||
<< "*.tif" << "*.tiff" << "*.wld" << "*.xml";
|
<< "*.tfw" << "*.tif" << "*.tiff" << "*.wld" << "*.xml";
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
441
src/map/qctmap.cpp
Normal file
441
src/map/qctmap.cpp
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
#include <cstring>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QPixmapCache>
|
||||||
|
#include <QPainter>
|
||||||
|
#include "common/color.h"
|
||||||
|
#include "qctmap.h"
|
||||||
|
|
||||||
|
#define TILE_SIZE 64
|
||||||
|
#define TILE_PIXELS (TILE_SIZE * TILE_SIZE)
|
||||||
|
#define MAGIC 0x1423D5FF
|
||||||
|
|
||||||
|
static quint8 bpp(quint8 colours)
|
||||||
|
{
|
||||||
|
if (colours <= 2)
|
||||||
|
return 1;
|
||||||
|
if (colours <= 4)
|
||||||
|
return 2;
|
||||||
|
if (colours <= 8)
|
||||||
|
return 3;
|
||||||
|
if (colours <= 16)
|
||||||
|
return 4;
|
||||||
|
if (colours <= 32)
|
||||||
|
return 5;
|
||||||
|
if (colours <= 64)
|
||||||
|
return 6;
|
||||||
|
if (colours <= 128)
|
||||||
|
return 7;
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validateTable(const QVector<quint8> &table)
|
||||||
|
{
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
for (int i = 0; i < table.size(); i++) {
|
||||||
|
if (table.at(i) == 128) {
|
||||||
|
if (i + 2 >= table.size())
|
||||||
|
return false;
|
||||||
|
delta = 65537 - (256 * table.at(i+2) + table.at(i+1)) + 2;
|
||||||
|
if (i + delta >= table.size())
|
||||||
|
return false;
|
||||||
|
i += 2;
|
||||||
|
} else if (table.at(i) > 128) {
|
||||||
|
delta = 257 - table.at(i);
|
||||||
|
if (i + delta >= table.size())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createTable(QDataStream &stream, QVector<quint8> &table)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
int colours = 0;
|
||||||
|
int branches = 0;
|
||||||
|
|
||||||
|
table.reserve(256);
|
||||||
|
|
||||||
|
while (stream.status() == QDataStream::Ok && colours <= branches) {
|
||||||
|
table.resize(table.size() + 1);
|
||||||
|
stream >> table[idx];
|
||||||
|
|
||||||
|
if (table[idx] == 128) {
|
||||||
|
table.resize(table.size() + 2);
|
||||||
|
stream >> table[++idx];
|
||||||
|
stream >> table[++idx];
|
||||||
|
branches++;
|
||||||
|
} else if (table[idx] > 128)
|
||||||
|
branches++;
|
||||||
|
else
|
||||||
|
colours++;
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool huffman(QDataStream &stream, quint8 tileData[TILE_PIXELS])
|
||||||
|
{
|
||||||
|
QVector<quint8> table;
|
||||||
|
if (!createTable(stream, table))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (table.size() == 1) {
|
||||||
|
memset(tileData, table[0], TILE_PIXELS);
|
||||||
|
} else {
|
||||||
|
if (!validateTable(table))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const quint8 *tp = table.constData();
|
||||||
|
int bitsLeft = 8;
|
||||||
|
int bitVal;
|
||||||
|
quint8 val;
|
||||||
|
|
||||||
|
stream >> val;
|
||||||
|
|
||||||
|
for (int pixelnum = 0; pixelnum < TILE_PIXELS; ) {
|
||||||
|
if (*tp < 128) {
|
||||||
|
tileData[pixelnum++] = *tp;
|
||||||
|
tp = table.constData();
|
||||||
|
} else {
|
||||||
|
bitVal = (val & 1);
|
||||||
|
|
||||||
|
val >>= 1;
|
||||||
|
bitsLeft--;
|
||||||
|
if (bitsLeft == 0) {
|
||||||
|
stream >> val;
|
||||||
|
bitsLeft = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitVal == 0) {
|
||||||
|
if (*tp == 128)
|
||||||
|
tp += 2;
|
||||||
|
tp++;
|
||||||
|
} else {
|
||||||
|
if (*tp > 128)
|
||||||
|
tp += 257 - (*tp);
|
||||||
|
else if (*tp == 128)
|
||||||
|
tp += 65537 - (256 * tp[2] + tp[1]) + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pixelPacking(QDataStream &stream, quint8 tileData[TILE_PIXELS],
|
||||||
|
quint8 colours)
|
||||||
|
{
|
||||||
|
quint8 shift = bpp(colours);
|
||||||
|
quint32 mask = (1 << shift) - 1;
|
||||||
|
int wordSize = 32 / shift;
|
||||||
|
quint8 paletteIndex[256];
|
||||||
|
|
||||||
|
for (quint8 i = 0; i < colours; i++)
|
||||||
|
stream >> paletteIndex[i];
|
||||||
|
|
||||||
|
for (int pixelnum = 0; pixelnum < TILE_PIXELS; ) {
|
||||||
|
quint32 colour, val;
|
||||||
|
stream >> val;
|
||||||
|
|
||||||
|
for (int runs = 0; runs < wordSize; runs++) {
|
||||||
|
colour = val & mask;
|
||||||
|
val = val >> shift;
|
||||||
|
tileData[pixelnum++] = paletteIndex[colour];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rle(QDataStream &stream, quint8 tileData[TILE_PIXELS],
|
||||||
|
quint8 colours)
|
||||||
|
{
|
||||||
|
quint8 bits = bpp(colours);
|
||||||
|
quint8 paletteMask = (1 << bits) - 1;
|
||||||
|
quint8 paletteIndex[256];
|
||||||
|
quint8 val;
|
||||||
|
|
||||||
|
for (quint8 i = 0; i < colours; i++)
|
||||||
|
stream >> paletteIndex[i];
|
||||||
|
|
||||||
|
for (int pixelnum = 0; pixelnum < TILE_PIXELS; ) {
|
||||||
|
stream >> val;
|
||||||
|
|
||||||
|
quint8 colour = val & paletteMask;
|
||||||
|
quint8 runs = val >> bits;
|
||||||
|
|
||||||
|
while (runs-- > 0)
|
||||||
|
tileData[pixelnum++] = paletteIndex[colour];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool readString(QDataStream &stream, quint32 offset, QString &str)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
QByteArray ba;
|
||||||
|
|
||||||
|
if (!stream.device()->seek(offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (stream.readRawData(&c, 1) == 1) {
|
||||||
|
if (c)
|
||||||
|
ba.append(c);
|
||||||
|
else {
|
||||||
|
str = QString::fromUtf8(ba);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCTMap::readHeader(QDataStream &stream)
|
||||||
|
{
|
||||||
|
quint32 version, title, ext, shift;
|
||||||
|
|
||||||
|
stream >> version >> _cols >> _rows >> title;
|
||||||
|
if (stream.status() != QDataStream::Ok)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!readString(stream, title, _name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!stream.device()->seek(0x54))
|
||||||
|
return false;
|
||||||
|
stream >> ext;
|
||||||
|
if (stream.status() != QDataStream::Ok)
|
||||||
|
return false;
|
||||||
|
if (!stream.device()->seek(ext + 4))
|
||||||
|
return false;
|
||||||
|
stream >> shift;
|
||||||
|
if (stream.status() != QDataStream::Ok)
|
||||||
|
return false;
|
||||||
|
if (!stream.device()->seek(shift))
|
||||||
|
return false;
|
||||||
|
stream >> _shiftN >> _shiftE;
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCTMap::readGeoRef(QDataStream &stream)
|
||||||
|
{
|
||||||
|
if (!stream.device()->seek(0x60))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
stream >> _eas >> _easY >> _easX >> _easYY >> _easXY >> _easXX >> _easYYY
|
||||||
|
>> _easYYX >> _easXXY >> _easXXX >> _nor >> _norY >> _norX >> _norYY
|
||||||
|
>> _norXY >> _norXX >> _norYYY >> _norYYX >> _norXXY >> _norXXX;
|
||||||
|
stream >> _lat >> _latX >> _latY >> _latXX >> _latXY >> _latYY >> _latXXX
|
||||||
|
>> _latXXY >> _latXYY >> _latYYY >> _lon >> _lonX >> _lonY >> _lonXX
|
||||||
|
>> _lonXY >> _lonYY >> _lonXXX >> _lonXXY >> _lonXYY >> _lonYYY;
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCTMap::readPalette(QDataStream &stream)
|
||||||
|
{
|
||||||
|
if (!stream.device()->seek(0x01A0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_palette.resize(256);
|
||||||
|
|
||||||
|
quint32 bgr;
|
||||||
|
for (int i = 0; i < _palette.size(); i++) {
|
||||||
|
stream >> bgr;
|
||||||
|
_palette[i] = Color::bgr2rgb(bgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCTMap::readIndex(QDataStream &stream)
|
||||||
|
{
|
||||||
|
if (!stream.device()->seek(0x45A0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_index.resize(_cols * _rows);
|
||||||
|
for (int i = 0; i < _cols * _rows; i++)
|
||||||
|
stream >> _index[i];
|
||||||
|
|
||||||
|
return (stream.status() == QDataStream::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCTMap::QCTMap(const QString &fileName, QObject *parent)
|
||||||
|
: Map(fileName, parent), _file(fileName), _mapRatio(1.0), _valid(false)
|
||||||
|
{
|
||||||
|
if (!_file.open(QIODevice::ReadOnly)) {
|
||||||
|
_errorString = fileName + ": " + _file.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream stream(&_file);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
quint32 magic;
|
||||||
|
|
||||||
|
stream >> magic;
|
||||||
|
if (magic != MAGIC) {
|
||||||
|
_errorString = "Not a QCT map";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!readHeader(stream)) {
|
||||||
|
_errorString = "Error reading QCT header";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!readGeoRef(stream)) {
|
||||||
|
_errorString = "Error reading georeference info";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!readPalette(stream)) {
|
||||||
|
_errorString = "Error reading colour palette";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!readIndex(stream)) {
|
||||||
|
_errorString = "Error reading tile index";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_file.close();
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCTMap::load()
|
||||||
|
{
|
||||||
|
_file.open(QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCTMap::unload()
|
||||||
|
{
|
||||||
|
_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF QCTMap::bounds()
|
||||||
|
{
|
||||||
|
return QRectF(QPointF(0, 0), QSizeF(_cols * TILE_SIZE, _rows * TILE_SIZE)
|
||||||
|
/ _mapRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF QCTMap::ll2xy(const Coordinates &c)
|
||||||
|
{
|
||||||
|
double lon = c.lon() - _shiftE;
|
||||||
|
double lon2 = lon * lon;
|
||||||
|
double lon3 = lon2 * lon;
|
||||||
|
double lat = c.lat() - _shiftN;
|
||||||
|
double lat2 = lat * lat;
|
||||||
|
double lat3 = lat2 * lat;
|
||||||
|
|
||||||
|
double x = _easXXX*lon3 + _easXX*lon2 + _easX*lon + _easYYY*lat3
|
||||||
|
+ _easYY*lat2 + _easY*lat + _easXXY*lon2*lat
|
||||||
|
+ _easYYX*lat2*lon + _easXY*lon*lat + _eas;
|
||||||
|
double y = _norXXX*lon3 + _norXX*lon2 + _norX*lon + _norYYY*lat3
|
||||||
|
+ _norYY*lat2 + _norY*lat + _norXXY*lon2*lat
|
||||||
|
+ _norYYX*lat2*lon + _norXY*lon*lat + _nor;
|
||||||
|
|
||||||
|
return QPointF(x - _shiftE, y - _shiftN) / _mapRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates QCTMap::xy2ll(const QPointF &p)
|
||||||
|
{
|
||||||
|
qreal x = p.x() * _mapRatio;
|
||||||
|
qreal x2 = x * x;
|
||||||
|
qreal x3 = x2 * x;
|
||||||
|
qreal y = p.y() * _mapRatio;
|
||||||
|
qreal y2 = y * y;
|
||||||
|
qreal y3 = y2 * y;
|
||||||
|
|
||||||
|
double lon = _lon + _lonX*x + _lonY*y + _lonXX*x2
|
||||||
|
+ _lonXY*x*y + _lonYY*y2 + _lonXXX*x3 + _lonXXY*x2*y
|
||||||
|
+ _lonXYY*x*y2 + _lonYYY*y3;
|
||||||
|
double lat = _lat + _latX*x + _latY*y + _latXX*x2
|
||||||
|
+ _latXY*x*y + _latYY*y2 + _latXXX*x3 + _latXXY*x2 * y
|
||||||
|
+ _latXYY*x*y2 + _latYYY*y3;
|
||||||
|
|
||||||
|
return Coordinates(lon + _shiftE, lat + _shiftN);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap QCTMap::tile(int x, int y)
|
||||||
|
{
|
||||||
|
static quint8 rowSeq[] = {
|
||||||
|
0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
|
||||||
|
2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
|
||||||
|
1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
|
||||||
|
3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63
|
||||||
|
};
|
||||||
|
quint8 tileData[TILE_PIXELS], imgData[TILE_PIXELS];
|
||||||
|
quint8 packing;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
|
||||||
|
if (!_file.seek(_index.at(y * _cols + x)))
|
||||||
|
return QPixmap();
|
||||||
|
|
||||||
|
QDataStream stream(&_file);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
stream >> packing;
|
||||||
|
if (stream.status() != QDataStream::Ok)
|
||||||
|
return QPixmap();
|
||||||
|
|
||||||
|
if (packing == 0 || packing == 255)
|
||||||
|
ret = huffman(stream, tileData);
|
||||||
|
else if (packing > 127)
|
||||||
|
ret = pixelPacking(stream, tileData, 256 - packing);
|
||||||
|
else
|
||||||
|
ret = rle(stream, tileData, packing);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
return QPixmap();
|
||||||
|
|
||||||
|
for (int i = 0; i < TILE_SIZE; i++)
|
||||||
|
memcpy(imgData + i * TILE_SIZE, tileData + rowSeq[i] * TILE_SIZE,
|
||||||
|
TILE_SIZE);
|
||||||
|
|
||||||
|
QImage img(imgData, TILE_SIZE, TILE_SIZE, TILE_SIZE,
|
||||||
|
QImage::Format_Indexed8);
|
||||||
|
img.setColorTable(_palette);
|
||||||
|
|
||||||
|
return QPixmap::fromImage(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCTMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
|
{
|
||||||
|
Q_UNUSED(flags);
|
||||||
|
|
||||||
|
QSizeF ts(TILE_SIZE / _mapRatio, TILE_SIZE / _mapRatio);
|
||||||
|
QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
|
||||||
|
floor(rect.top() / ts.height()) * ts.height());
|
||||||
|
|
||||||
|
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
||||||
|
for (int i = 0; i < ceil(s.width() / ts.width()); i++) {
|
||||||
|
for (int j = 0; j < ceil(s.height() / ts.height()); j++) {
|
||||||
|
int x = round(tl.x() * _mapRatio + i * TILE_SIZE) / TILE_SIZE;
|
||||||
|
int y = round(tl.y() * _mapRatio + j * TILE_SIZE) / TILE_SIZE;
|
||||||
|
|
||||||
|
QPixmap pixmap;
|
||||||
|
QString key = path() + "/" + QString::number(x) + "_"
|
||||||
|
+ QString::number(y);
|
||||||
|
if (!QPixmapCache::find(key, &pixmap)) {
|
||||||
|
pixmap = tile(x, y);
|
||||||
|
if (!pixmap.isNull())
|
||||||
|
QPixmapCache::insert(key, pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixmap.isNull())
|
||||||
|
qWarning("%s: error loading tile image", qPrintable(key));
|
||||||
|
else {
|
||||||
|
pixmap.setDevicePixelRatio(_mapRatio);
|
||||||
|
QPointF tp(tl.x() + i * ts.width(), tl.y() + j * ts.height());
|
||||||
|
painter->drawPixmap(tp, pixmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
src/map/qctmap.h
Normal file
60
src/map/qctmap.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef QCTMAP_H
|
||||||
|
#define QCTMAP_H
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QRgb>
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
class QDataStream;
|
||||||
|
|
||||||
|
class QCTMap : public Map
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QCTMap(const QString &fileName, QObject *parent = 0);
|
||||||
|
|
||||||
|
QString name() const {return _name;}
|
||||||
|
|
||||||
|
QRectF bounds();
|
||||||
|
|
||||||
|
QPointF ll2xy(const Coordinates &c);
|
||||||
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
void setDevicePixelRatio(qreal /*deviceRatio*/, qreal mapRatio)
|
||||||
|
{_mapRatio = mapRatio;}
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool readHeader(QDataStream &stream);
|
||||||
|
bool readGeoRef(QDataStream &stream);
|
||||||
|
bool readIndex(QDataStream &stream);
|
||||||
|
bool readPalette(QDataStream &stream);
|
||||||
|
QPixmap tile(int x, int y);
|
||||||
|
|
||||||
|
QFile _file;
|
||||||
|
QString _name;
|
||||||
|
int _rows, _cols;
|
||||||
|
double _lon, _lonX, _lonXX, _lonXXX, _lonY, _lonYY, _lonYYY, _lonXY,
|
||||||
|
_lonXXY, _lonXYY;
|
||||||
|
double _lat, _latX, _latXX, _latXXX, _latY, _latYY, _latYYY, _latXY,
|
||||||
|
_latXXY, _latXYY;
|
||||||
|
double _eas, _easY, _easX, _easYY, _easXY, _easXX, _easYYY, _easYYX,
|
||||||
|
_easXXY, _easXXX;
|
||||||
|
double _nor, _norY, _norX, _norYY, _norXY, _norXX, _norYYY, _norYYX,
|
||||||
|
_norXXY, _norXXX;
|
||||||
|
double _shiftE, _shiftN;
|
||||||
|
QVector<quint32> _index;
|
||||||
|
QVector<QRgb> _palette;
|
||||||
|
|
||||||
|
qreal _mapRatio;
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QCTMAP_H
|
Loading…
Reference in New Issue
Block a user