mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-02-17 16:20:48 +01:00
Added support for BSB charts maps
This commit is contained in:
parent
609e73256a
commit
96733883cb
@ -103,6 +103,7 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/IMG/rastertile.h \
|
src/map/IMG/rastertile.h \
|
||||||
src/map/IMG/textpathitem.h \
|
src/map/IMG/textpathitem.h \
|
||||||
src/map/IMG/textpointitem.h \
|
src/map/IMG/textpointitem.h \
|
||||||
|
src/map/bsbmap.h \
|
||||||
src/map/projection.h \
|
src/map/projection.h \
|
||||||
src/map/ellipsoid.h \
|
src/map/ellipsoid.h \
|
||||||
src/map/datum.h \
|
src/map/datum.h \
|
||||||
@ -271,6 +272,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/IMG/rastertile.cpp \
|
src/map/IMG/rastertile.cpp \
|
||||||
src/map/IMG/textpathitem.cpp \
|
src/map/IMG/textpathitem.cpp \
|
||||||
src/map/IMG/textpointitem.cpp \
|
src/map/IMG/textpointitem.cpp \
|
||||||
|
src/map/bsbmap.cpp \
|
||||||
src/map/maplist.cpp \
|
src/map/maplist.cpp \
|
||||||
src/map/onlinemap.cpp \
|
src/map/onlinemap.cpp \
|
||||||
src/map/downloader.cpp \
|
src/map/downloader.cpp \
|
||||||
|
450
src/map/bsbmap.cpp
Normal file
450
src/map/bsbmap.cpp
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
#include <cctype>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QPainter>
|
||||||
|
#include "image.h"
|
||||||
|
#include "gcs.h"
|
||||||
|
#include "pcs.h"
|
||||||
|
#include "calibrationpoint.h"
|
||||||
|
#include "color.h"
|
||||||
|
#include "bsbmap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define LINE_LIMIT 1024
|
||||||
|
|
||||||
|
static inline bool getChar(QFile &file, bool mangled, char *c)
|
||||||
|
{
|
||||||
|
if (!file.getChar(c))
|
||||||
|
return false;
|
||||||
|
if (mangled)
|
||||||
|
*c = (char)((int)(*c - 9) & 0xFF);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isEOH(const QByteArray &line)
|
||||||
|
{
|
||||||
|
return (line.size() >= 2 && line.at(line.size() - 2) == 0x1A
|
||||||
|
&& line.at(line.size() -1) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isType(const QByteArray &line, const QByteArray &type)
|
||||||
|
{
|
||||||
|
return (line.left(4) == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QByteArray hdrData(const QByteArray &line)
|
||||||
|
{
|
||||||
|
return line.right(line.size() - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool readHeaderLine(QFile &file, bool mangled, QByteArray &line)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while (getChar(file, mangled, &c) && line.size() < LINE_LIMIT) {
|
||||||
|
if (c == '\0') {
|
||||||
|
line.append(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
if (!getChar(file, mangled, &c))
|
||||||
|
return false;
|
||||||
|
if (c == ' ') {
|
||||||
|
do {
|
||||||
|
if (!getChar(file, mangled, &c))
|
||||||
|
return false;
|
||||||
|
} while (c == ' ');
|
||||||
|
line.append(',');
|
||||||
|
file.ungetChar(c);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
file.ungetChar(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isSplitter(const QByteArray &line, int i)
|
||||||
|
{
|
||||||
|
return (line.at(i) == ',' && line.size() - i > 3 && isupper(line.at(i+1))
|
||||||
|
&& (isupper(line.at(i+2)) || isdigit(line.at(i+2))) && line.at(i+3) == '=');
|
||||||
|
}
|
||||||
|
|
||||||
|
static QList<QByteArray> split(const QByteArray &line)
|
||||||
|
{
|
||||||
|
QList<QByteArray> list;
|
||||||
|
int ls = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < line.size(); i++) {
|
||||||
|
if (isSplitter(line, i)) {
|
||||||
|
list.append(line.mid(ls, i - ls));
|
||||||
|
ls = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.append(line.mid(ls, line.size() - ls));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QMap<QString, QString> kvMap(const QByteArray &line)
|
||||||
|
{
|
||||||
|
QMap<QString, QString> map;
|
||||||
|
QList<QByteArray> parts(split(line));
|
||||||
|
|
||||||
|
for (int i = 0; i < parts.size(); i++) {
|
||||||
|
QList<QByteArray> ba = parts.at(i).split('=');
|
||||||
|
if (ba.size() != 2)
|
||||||
|
continue;
|
||||||
|
map.insert(ba.at(0), ba.at(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double parameter(const QString &str, bool *res)
|
||||||
|
{
|
||||||
|
if (str.isEmpty() || str == "NOT_APPLICABLE") {
|
||||||
|
*res = true;
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.toDouble(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool BSBMap::parseBSB(const QByteArray &line)
|
||||||
|
{
|
||||||
|
QMap<QString, QString> map(kvMap(line));
|
||||||
|
|
||||||
|
_name = map.value("NA");
|
||||||
|
if (_name.isEmpty()) {
|
||||||
|
_errorString = "Invalid/missing BSB NA field";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList sv(map.value("RA").split(','));
|
||||||
|
unsigned w, h;
|
||||||
|
bool wok = false, hok = false;
|
||||||
|
if (sv.size() == 2) {
|
||||||
|
w = sv.at(0).toUInt(&wok);
|
||||||
|
h = sv.at(1).toUInt(&hok);
|
||||||
|
} else if (sv.size() == 4) {
|
||||||
|
w = sv.at(2).toUInt(&wok);
|
||||||
|
h = sv.at(3).toUInt(&hok);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wok || !hok || !w || !h) {
|
||||||
|
_errorString = "Invalid BSB RA field";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_size = QSize(w, h);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::parseKNP(const QByteArray &line, QString &datum, QString &proj,
|
||||||
|
double &pp)
|
||||||
|
{
|
||||||
|
QMap<QString, QString> map(kvMap(line));
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (!(map.contains("PR") && map.contains("GD") && map.contains("PP"))) {
|
||||||
|
_errorString = "Missing KNP PR/GD/PP field";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
proj = map.value("PR");
|
||||||
|
datum = map.value("GD");
|
||||||
|
|
||||||
|
pp = parameter(map.value("PP"), &ok);
|
||||||
|
if (!ok) {
|
||||||
|
_errorString = "Invalid KNP PP field";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::parseKNQ(const QByteArray &line, double &p2, double &p3)
|
||||||
|
{
|
||||||
|
QMap<QString, QString> map(kvMap(line));
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
p2 = parameter(map.value("P2"), &ok);
|
||||||
|
if (!ok) {
|
||||||
|
_errorString = "Invalid KNQ P2 parameter";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p3 = parameter(map.value("P3"), &ok);
|
||||||
|
if (!ok) {
|
||||||
|
_errorString = "Invalid KNQ P3 parameter";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::parseREF(const QByteArray &line, QList<ReferencePoint> &points)
|
||||||
|
{
|
||||||
|
QList<QByteArray> fields(line.split(','));
|
||||||
|
|
||||||
|
if (fields.size() == 5) {
|
||||||
|
bool xok, yok, lonok, latok;
|
||||||
|
CalibrationPoint p(PointD(fields.at(1).toDouble(&xok),
|
||||||
|
fields.at(2).toDouble(&yok)), Coordinates(fields.at(4).toDouble(&lonok),
|
||||||
|
fields.at(3).toDouble(&latok)));
|
||||||
|
if (xok && yok && lonok && latok) {
|
||||||
|
points.append(p.rp(_projection));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = QString(line) + ": Invalid reference point entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::parseRGB(const QByteArray &line)
|
||||||
|
{
|
||||||
|
QList<QByteArray> fields(line.split(','));
|
||||||
|
bool iok, rok, gok, bok;
|
||||||
|
int i = fields.at(0).toUInt(&iok);
|
||||||
|
|
||||||
|
if (fields.size() == 4 && i > 0 && i < 256) {
|
||||||
|
_palette[i-1] = Color::rgb(fields.at(1).toUInt(&rok),
|
||||||
|
fields.at(2).toUInt(&gok), fields.at(3).toUInt(&bok));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = QString(line) + ": Invalid RGB entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::readHeader(QFile &file, bool mangled)
|
||||||
|
{
|
||||||
|
QByteArray line;
|
||||||
|
QString datum, proj;
|
||||||
|
double pp, p2, p3;
|
||||||
|
QList<ReferencePoint> points;
|
||||||
|
|
||||||
|
while (readHeaderLine(file, mangled, line)) {
|
||||||
|
if (isEOH(line)) {
|
||||||
|
if (!_size.isValid() || !_projection.isValid()) {
|
||||||
|
_errorString = "Invalid KAP/NOS file header";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return createTransform(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isType(line, "BSB/") || isType(line, "NOS/"))
|
||||||
|
&& !parseBSB(hdrData(line)))
|
||||||
|
return false;
|
||||||
|
else if (isType(line, "KNP/") && !parseKNP(hdrData(line), datum, proj,
|
||||||
|
pp))
|
||||||
|
return false;
|
||||||
|
else if (isType(line, "KNQ/") && !parseKNQ(hdrData(line), p2, p3))
|
||||||
|
return false;
|
||||||
|
else if (isType(line, "REF/")) {
|
||||||
|
if (_projection.isNull()) {
|
||||||
|
if (!createProjection(datum, proj, pp, p2, p3))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parseREF(hdrData(line), points))
|
||||||
|
return false;
|
||||||
|
} else if (isType(line, "RGB/") && !parseRGB(hdrData(line)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
line.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = "Not a KAP/NOS file";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::createTransform(const QList<ReferencePoint> &points)
|
||||||
|
{
|
||||||
|
_transform = Transform(points);
|
||||||
|
if (!_transform.isValid()) {
|
||||||
|
_errorString = _transform.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::createProjection(const QString &datum, const QString &proj,
|
||||||
|
double pp, double p2, double p3)
|
||||||
|
{
|
||||||
|
const GCS *gcs = 0;
|
||||||
|
PCS pcs;
|
||||||
|
|
||||||
|
if (datum.isEmpty())
|
||||||
|
gcs = GCS::gcs(4326);
|
||||||
|
else
|
||||||
|
gcs = GCS::gcs(datum);
|
||||||
|
if (!gcs) {
|
||||||
|
_errorString = datum + ": Unknown datum";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proj.compare("MERCATOR", Qt::CaseInsensitive)) {
|
||||||
|
Projection::Setup setup(0, 0, 1, 0, 0, 0, 0);
|
||||||
|
pcs = PCS(gcs, 9804, setup, 9001);
|
||||||
|
} else if (proj.compare("TRANSVERSE MERCATOR", Qt::CaseInsensitive)) {
|
||||||
|
Projection::Setup setup(0, pp, 1, 0, 0, 0, 0);
|
||||||
|
pcs = PCS(gcs, 9807, setup, 9001);
|
||||||
|
} else if (proj.compare("UNIVERSAL TRANSVERSE MERCATOR",
|
||||||
|
Qt::CaseInsensitive)) {
|
||||||
|
Projection::Setup setup(0, pp, 0.9996, 500000, 0, 0, 0);
|
||||||
|
pcs = PCS(gcs, 9807, setup, 9001);
|
||||||
|
} else if (proj.compare("LAMBERT CONFORMAL CONIC", Qt::CaseInsensitive)) {
|
||||||
|
Projection::Setup setup(0, pp, 1, 0, 0, p2, p3);
|
||||||
|
pcs = PCS(gcs, 9802, setup, 9001);
|
||||||
|
} else {
|
||||||
|
_errorString = proj + ": Unknown/missing projection";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_projection = Projection(&pcs);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BSBMap::readRow(QFile &file, char bits, uchar *buf)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
int multiplier;
|
||||||
|
int pixel = 1, written = 0;
|
||||||
|
static const char mask[] = {0, 63, 31, 15, 7, 3, 1, 0};
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!getChar(file, _mangled, &c))
|
||||||
|
return false;
|
||||||
|
} while ((uchar)c >= 0x80);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!getChar(file, _mangled, &c))
|
||||||
|
return false;
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
pixel = (c & 0x7f) >> (7 - bits);
|
||||||
|
multiplier = c & mask[(int)bits];
|
||||||
|
|
||||||
|
while ((uchar)c >= 0x80) {
|
||||||
|
if (!getChar(file, _mangled, &c))
|
||||||
|
return false;
|
||||||
|
multiplier = (multiplier << 7) + (c & 0x7f);
|
||||||
|
}
|
||||||
|
multiplier++;
|
||||||
|
if (written + multiplier > _size.width())
|
||||||
|
multiplier = _size.width() - written;
|
||||||
|
memset(buf + written, pixel - 1, multiplier);
|
||||||
|
written += multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (written < _size.width())
|
||||||
|
buf[written++] = pixel - 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage BSBMap::readImage()
|
||||||
|
{
|
||||||
|
QFile file(_fileName);
|
||||||
|
char bits;
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
|
return QImage();
|
||||||
|
file.seek(_dataOffset);
|
||||||
|
if (!getChar(file, _mangled, &bits))
|
||||||
|
return QImage();
|
||||||
|
|
||||||
|
QImage img(_size, QImage::Format_Indexed8);
|
||||||
|
img.setColorTable(_palette);
|
||||||
|
|
||||||
|
for (int row = 0; row < _size.height(); row++) {
|
||||||
|
uchar *bsb_row = img.scanLine(row);
|
||||||
|
if (!readRow(file, bits, bsb_row))
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
BSBMap::BSBMap(const QString &fileName, QObject *parent)
|
||||||
|
: Map(parent), _fileName(fileName), _img(0), _ratio(1.0), _dataOffset(-1),
|
||||||
|
_valid(false)
|
||||||
|
{
|
||||||
|
QFileInfo fi(fileName);
|
||||||
|
QFile file(fileName);
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
_errorString = fileName + ": " + file.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_palette.resize(256);
|
||||||
|
_mangled = !fi.suffix().compare("no1", Qt::CaseInsensitive);
|
||||||
|
if (!readHeader(file, _mangled))
|
||||||
|
return;
|
||||||
|
_dataOffset = file.pos();
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BSBMap::~BSBMap()
|
||||||
|
{
|
||||||
|
delete _img;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF BSBMap::ll2xy(const Coordinates &c)
|
||||||
|
{
|
||||||
|
return QPointF(_transform.proj2img(_projection.ll2xy(c))) / _ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates BSBMap::xy2ll(const QPointF &p)
|
||||||
|
{
|
||||||
|
return _projection.xy2ll(_transform.img2proj(p * _ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF BSBMap::bounds()
|
||||||
|
{
|
||||||
|
return QRectF(QPointF(0, 0), _size / _ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSBMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
|
{
|
||||||
|
if (_img)
|
||||||
|
_img->draw(painter, rect, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSBMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
|
||||||
|
{
|
||||||
|
Q_UNUSED(deviceRatio);
|
||||||
|
|
||||||
|
_ratio = mapRatio;
|
||||||
|
if (_img)
|
||||||
|
_img->setDevicePixelRatio(_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSBMap::load()
|
||||||
|
{
|
||||||
|
if (!_img)
|
||||||
|
_img = new Image(readImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSBMap::unload()
|
||||||
|
{
|
||||||
|
delete _img;
|
||||||
|
_img = 0;
|
||||||
|
}
|
64
src/map/bsbmap.h
Normal file
64
src/map/bsbmap.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef BSBMAP_H
|
||||||
|
#define BSBMAP_H
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include "transform.h"
|
||||||
|
#include "projection.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
class QFile;
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
class BSBMap : public Map
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BSBMap(const QString &fileName, QObject *parent = 0);
|
||||||
|
~BSBMap();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool parseBSB(const QByteArray &line);
|
||||||
|
bool parseKNP(const QByteArray &line, QString &datum, QString &proj,
|
||||||
|
double &pp);
|
||||||
|
bool parseKNQ(const QByteArray &line, double &p2, double &p3);
|
||||||
|
bool parseREF(const QByteArray &line, QList<ReferencePoint> &points);
|
||||||
|
bool parseRGB(const QByteArray &line);
|
||||||
|
bool readHeader(QFile &file, bool mangled);
|
||||||
|
bool createProjection(const QString &datum, const QString &proj,
|
||||||
|
double pp, double p2, double p3);
|
||||||
|
bool createTransform(const QList<ReferencePoint> &points);
|
||||||
|
QImage readImage();
|
||||||
|
bool readRow(QFile &file, char bits, uchar *buf);
|
||||||
|
|
||||||
|
QString _fileName;
|
||||||
|
QString _name;
|
||||||
|
Projection _projection;
|
||||||
|
Transform _transform;
|
||||||
|
Image *_img;
|
||||||
|
QSize _size;
|
||||||
|
qreal _ratio;
|
||||||
|
qint64 _dataOffset;
|
||||||
|
bool _mangled;
|
||||||
|
QVector<QRgb> _palette;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BSBMAP_H
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef CALIBRATIONPOINT_H
|
#ifndef CALIBRATIONPOINT_H
|
||||||
#define CALIBRATIONPOINT_H
|
#define CALIBRATIONPOINT_H
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include "projection.h"
|
#include "projection.h"
|
||||||
|
|
||||||
@ -22,10 +23,21 @@ public:
|
|||||||
: ReferencePoint(_xy, _pp);
|
: ReferencePoint(_xy, _pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend QDebug operator<<(QDebug dbg, const CalibrationPoint &p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PointD _xy;
|
PointD _xy;
|
||||||
PointD _pp;
|
PointD _pp;
|
||||||
Coordinates _ll;
|
Coordinates _ll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
inline QDebug operator<<(QDebug dbg, const CalibrationPoint &p)
|
||||||
|
{
|
||||||
|
dbg.nospace() << "CalibrationPoint(" << p._xy << ", " << p._pp << ", "
|
||||||
|
<< p._ll << ")";
|
||||||
|
return dbg.space();
|
||||||
|
}
|
||||||
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
#endif // CALIBRATIONPOINT_H
|
#endif // CALIBRATIONPOINT_H
|
||||||
|
@ -13,6 +13,11 @@ namespace Color
|
|||||||
|
|
||||||
return (0xFF000000 | r << 16 | g << 8 | b);
|
return (0xFF000000 | r << 16 | g << 8 | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QRgb rgb(quint32 r, quint32 g, quint32 b)
|
||||||
|
{
|
||||||
|
return (0xFF000000 | r << 16 | g << 8 | b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COLOR_H
|
#endif // COLOR_H
|
||||||
|
@ -54,6 +54,7 @@ QList<GCS::Entry> GCS::defaults()
|
|||||||
{
|
{
|
||||||
QList<GCS::Entry> list;
|
QList<GCS::Entry> list;
|
||||||
list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84()));
|
list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84()));
|
||||||
|
list.append(GCS::Entry(4326, 6326, "WGS84", WGS84()));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include "common/config.h"
|
|
||||||
#include "geotiff.h"
|
#include "geotiff.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "geotiffmap.h"
|
#include "geotiffmap.h"
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPixmapCache>
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
|
||||||
|
|
||||||
#define TILE_SIZE 256
|
#define TILE_SIZE 256
|
||||||
|
|
||||||
Image::Image(const QString &fileName) : _img(fileName), _fileName(fileName)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
|
void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
@ -19,26 +14,30 @@ void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
|
|||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
QRectF sr(rect.topLeft() * ratio, rect.size() * ratio);
|
QRectF sr(rect.topLeft() * ratio, rect.size() * ratio);
|
||||||
|
|
||||||
|
/* When OpenGL is used, big images are rendered incredibly slow or not at
|
||||||
|
all using the QPainter::drawImage() function with a source rect set. So
|
||||||
|
we have to tile the image ourself before it can be drawn.
|
||||||
|
|
||||||
|
We have to use a list of dynamically allocated pixmaps as QPainter
|
||||||
|
rendering is broken in yet another way with OpenGL and drawPixmap() does
|
||||||
|
access already deleted image instances when reusing a single pixmap. */
|
||||||
if (flags & Map::OpenGL) {
|
if (flags & Map::OpenGL) {
|
||||||
|
QList<QPixmap *> list;
|
||||||
|
|
||||||
for (int i = sr.left()/TILE_SIZE; i <= sr.right()/TILE_SIZE; i++) {
|
for (int i = sr.left()/TILE_SIZE; i <= sr.right()/TILE_SIZE; i++) {
|
||||||
for (int j = sr.top()/TILE_SIZE; j <= sr.bottom()/TILE_SIZE; j++) {
|
for (int j = sr.top()/TILE_SIZE; j <= sr.bottom()/TILE_SIZE; j++) {
|
||||||
QString key = _fileName + "-" + QString::number(i) + "_"
|
|
||||||
+ QString::number(j);
|
|
||||||
QPoint tl(i * TILE_SIZE, j * TILE_SIZE);
|
QPoint tl(i * TILE_SIZE, j * TILE_SIZE);
|
||||||
QPixmap pm;
|
|
||||||
|
|
||||||
if (!QPixmapCache::find(key, &pm)) {
|
|
||||||
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
|
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
|
||||||
pm = QPixmap::fromImage(_img.copy(tile));
|
QPixmap *pm = new QPixmap(QPixmap::fromImage(_img.copy(tile)));
|
||||||
if (!pm.isNull())
|
list.append(pm);
|
||||||
QPixmapCache::insert(key, pm);
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
pm.setDevicePixelRatio(ratio);
|
pm->setDevicePixelRatio(ratio);
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
painter->drawPixmap(tl/ratio, pm);
|
painter->drawPixmap(tl/ratio, *pm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDeleteAll(list);
|
||||||
} else
|
} else
|
||||||
painter->drawImage(rect.topLeft(), _img, sr);
|
painter->drawImage(rect.topLeft(), _img, sr);
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,14 @@ class QPainter;
|
|||||||
class Image
|
class Image
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Image(const QString &fileName);
|
Image(const QString &fileName) : _img(fileName) {}
|
||||||
|
Image(const QImage &img) : _img(img) {}
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, Map::Flags flags);
|
void draw(QPainter *painter, const QRectF &rect, Map::Flags flags);
|
||||||
void setDevicePixelRatio(qreal ratio);
|
void setDevicePixelRatio(qreal ratio);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QImage _img;
|
QImage _img;
|
||||||
QString _fileName;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMAGE_H
|
#endif // IMAGE_H
|
||||||
|
@ -144,7 +144,7 @@ JNXMap::JNXMap(const QString &fileName, QObject *parent)
|
|||||||
_name = QFileInfo(fileName).fileName();
|
_name = QFileInfo(fileName).fileName();
|
||||||
|
|
||||||
if (!_file.open(QIODevice::ReadOnly)) {
|
if (!_file.open(QIODevice::ReadOnly)) {
|
||||||
_errorString = QString("%1: Error opening file").arg(fileName);
|
_errorString = fileName + ": " + _file.errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "rmap.h"
|
#include "rmap.h"
|
||||||
#include "imgmap.h"
|
#include "imgmap.h"
|
||||||
#include "IMG/gmap.h"
|
#include "IMG/gmap.h"
|
||||||
|
#include "bsbmap.h"
|
||||||
#include "maplist.h"
|
#include "maplist.h"
|
||||||
|
|
||||||
|
|
||||||
@ -45,6 +46,8 @@ Map *MapList::loadFile(const QString &path, QString &errorString,
|
|||||||
map = new IMGMap(path);
|
map = new IMGMap(path);
|
||||||
else if (suffix == "map" || suffix == "tar")
|
else if (suffix == "map" || suffix == "tar")
|
||||||
map = new OziMap(path);
|
map = new OziMap(path);
|
||||||
|
else if (suffix == "kap" || suffix == "no1" || suffix == "nos")
|
||||||
|
map = new BSBMap(path);
|
||||||
|
|
||||||
if (map && map->isValid())
|
if (map && map->isValid())
|
||||||
return map;
|
return map;
|
||||||
@ -106,6 +109,7 @@ QString MapList::formats()
|
|||||||
+ qApp->translate("MapList", "Garmin IMG maps")
|
+ qApp->translate("MapList", "Garmin IMG maps")
|
||||||
+ " (*.gmap *.gmapi *.img *.xml);;"
|
+ " (*.gmap *.gmapi *.img *.xml);;"
|
||||||
+ qApp->translate("MapList", "Garmin JNX maps") + " (*.jnx);;"
|
+ qApp->translate("MapList", "Garmin JNX maps") + " (*.jnx);;"
|
||||||
|
+ qApp->translate("MapList", "BSB nautical charts") + " (*.kap *.no1 *.nos);;"
|
||||||
+ 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", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
||||||
@ -117,8 +121,8 @@ QString MapList::formats()
|
|||||||
QStringList MapList::filter()
|
QStringList MapList::filter()
|
||||||
{
|
{
|
||||||
QStringList filter;
|
QStringList filter;
|
||||||
filter << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.map"
|
filter << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.kap" << "*.map"
|
||||||
<< "*.mbtiles" << "*.rmap" << "*.rtmap" << "*.tar" << "*.tba" << "*.tif"
|
<< "*.mbtiles" << "*.no1" << "*.nos" << "*.rmap" << "*.rtmap" << "*.tar"
|
||||||
<< "*.tiff" << "*.xml";
|
<< "*.tba" << "*.tif" << "*.tiff" << "*.xml";
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user