1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-03 22:39:15 +02:00

Compare commits

...

15 Commits
13.8 ... 13.9

Author SHA1 Message Date
0531389cd8 Fixed storing of WMTS tiles with file system incompatible tile matrix names 2023-09-16 14:29:09 +02:00
a281a68cbd Decreased map zoom level treshold to 80%
There are evidently more maps that have bigger diferences in bounding box
latitudes which lead to differnt resolutions for the same zoom level in
Mercator projection than maps that would have zoom level differences < 20%.
2023-09-15 23:28:55 +02:00
2e7f8dc341 Fixed map resolution computation for maps > world/2 2023-09-15 23:28:16 +02:00
1304fd5c3c Use OpenSSL v3 for Windows Qt6 builds 2023-09-14 23:32:35 +02:00
d310399b4f Fixed Qt6 build 2023-09-14 19:02:19 +02:00
845a4b2921 Yet another TrekBuddy compatability enhancement & fixes
+ related map API refactoring
2023-09-14 18:36:03 +02:00
00fff55cd3 Check for bounds overflow in the computed/approximated case 2023-09-13 22:33:14 +02:00
722f3acb1e Support all variants of TrekBuddy maps/atlases
Added support for gmi calibration files and arbitrary named tba/map/gmi files.
2023-09-13 20:02:24 +02:00
b38cf31920 Allow arbitrary .map file names in TrekBuddy TAR maps 2023-09-12 22:05:42 +02:00
2884c39367 Contiguous zones 2023-09-12 08:47:39 +02:00
1124a1adb4 Distinguish silos and tanks 2023-09-10 11:41:38 +02:00
8c67df7bbd Version++ 2023-09-08 19:28:10 +02:00
d1e632523a Refactoring 2023-09-08 19:26:46 +02:00
2549ca2c90 Reference the exact S-57 document describing the catalogue 2023-09-08 19:25:52 +02:00
abd01933ab Less aggressive anchor/no-anchor lines 2023-09-08 19:24:51 +02:00
67 changed files with 672 additions and 316 deletions

View File

@ -1,4 +1,4 @@
version: 13.8.{build}
version: 13.9.{build}
configuration:
- Release
@ -8,10 +8,13 @@ image:
environment:
NSISDIR: C:\Program Files (x86)\NSIS
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
matrix:
- QTDIR: C:\Qt\5.15\msvc2019_64
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
OPENSSLVERSION: 1_1
- QTDIR: C:\Qt\6.5\msvc2019_64
OPENSSLDIR: C:\OpenSSL-v30-Win64\bin
OPENSSLVERSION: 3
NSISDEF: /DQT6
install:
@ -34,8 +37,8 @@ build_script:
xcopy lang\*.qm installer\translations\ /sy
xcopy icons\symbols installer\symbols /i
copy licence.txt installer
copy %OPENSSLDIR%\libcrypto-1_1-x64.dll installer
copy %OPENSSLDIR%\libssl-1_1-x64.dll installer
copy %OPENSSLDIR%\libcrypto-%OPENSSLVERSION%-x64.dll installer
copy %OPENSSLDIR%\libssl-%OPENSSLVERSION%-x64.dll installer
makensis.exe %NSISDEF% installer\gpxsee64.nsi

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else {
TARGET = GPXSee
}
VERSION = 13.8
VERSION = 13.9
QT += core \
@ -134,6 +134,7 @@ HEADERS += src/common/config.h \
src/map/encmap.h \
src/map/ENC/iso8211.h \
src/map/gemfmap.h \
src/map/gmifile.h \
src/map/oruxmap.h \
src/map/osmdroidmap.h \
src/map/proj/polyconic.h \
@ -347,6 +348,7 @@ SOURCES += src/main.cpp \
src/map/encmap.cpp \
src/map/ENC/iso8211.cpp \
src/map/gemfmap.cpp \
src/map/gmifile.cpp \
src/map/oruxmap.cpp \
src/map/osmdroidmap.cpp \
src/map/proj/polyconic.cpp \

View File

@ -188,6 +188,7 @@
<file alias="radar.png">icons/map/marine/radar.png</file>
<file alias="radar-transponder.png">icons/map/marine/radar-transponder.png</file>
<file alias="silo.png">icons/map/marine/silo.png</file>
<file alias="tank.png">icons/map/marine/tank.png</file>
<file alias="turning-basin.png">icons/map/marine/turning-basin.png</file>
<file alias="entry-prohibited-line.png">icons/map/marine/entry-prohibited-line.png</file>
<file alias="safety-zone-line.png">icons/map/marine/safety-zone-line.png</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

After

Width:  |  Height:  |  Size: 221 B

BIN
icons/map/marine/tank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

View File

@ -1648,7 +1648,7 @@
<key>UTTypeIdentifier</key>
<string>int.iho.s57-catalogue</string>
<key>UTTypeReferenceURL</key>
<string>https://iho.int/uploads/user/pubs/standards/s-57/31Main.pdf</string>
<string>https://iho.int/uploads/user/pubs/standards/s-57/20ApB1.pdf</string>
<key>UTTypeDescription</key>
<string>IHO S-57 Electronic Navigation Catalogue</string>
<key>UTTypeConformsTo</key>

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "13.8"
!define VERSION "13.9"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"
@ -302,8 +302,13 @@ Section "OpenSSL" SEC_OPENSSL
SectionIn RO
!ifdef QT6
File "libcrypto-3-x64.dll"
File "libssl-3-x64.dll"
!else
File "libcrypto-1_1-x64.dll"
File "libssl-1_1-x64.dll"
!endif
SectionEnd

View File

@ -1750,7 +1750,7 @@ bool GUI::loadMapNode(const TreeNode<Map*> &node, MapAction *&action,
bool GUI::loadMap(const QString &fileName, MapAction *&action, int &showError)
{
TreeNode<Map*> maps(MapList::loadMaps(fileName));
TreeNode<Map*> maps(MapList::loadMaps(fileName, _mapView->inputProjection()));
QList<QAction*> existingActions(_mapsActionGroup->actions());
return loadMapNode(maps, action, existingActions, showError);
@ -1854,7 +1854,7 @@ void GUI::loadMapDir()
return;
QFileInfo fi(dir);
TreeNode<Map*> maps(MapList::loadMaps(dir));
TreeNode<Map*> maps(MapList::loadMaps(dir, _mapView->inputProjection()));
QList<QAction*> existingActions(_mapsActionGroup->actions());
QList<MapAction*> actions;
QMenu *menu = new QMenu(maps.name());
@ -2985,7 +2985,7 @@ void GUI::loadInitialMaps(const QString &selected)
if (mapDir.isNull())
return;
TreeNode<Map*> maps(MapList::loadMaps(mapDir));
TreeNode<Map*> maps(MapList::loadMaps(mapDir, _mapView->inputProjection()));
createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd);
// Select the active map according to the user settings

View File

@ -81,15 +81,15 @@ ToolTip MapItem::info() const
return tt;
}
MapItem::MapItem(MapAction *action, Map *map, const Projection &proj,
GraphicsItem *parent) : PlaneItem(parent)
MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
: PlaneItem(parent)
{
Map *src = action->data().value<Map*>();
Q_ASSERT(map->isReady());
_name = src->name();
_fileName = src->path();
_bounds = src->llBounds(proj);
_bounds = src->llBounds();
connect(this, &MapItem::triggered, action, &MapAction::trigger);

View File

@ -11,8 +11,7 @@ class MapItem : public QObject, public PlaneItem
Q_OBJECT
public:
MapItem(MapAction *action, Map *map, const Projection &proj,
GraphicsItem *parent = 0);
MapItem(MapAction *action, Map *map, GraphicsItem *parent = 0);
QPainterPath shape() const {return _painterPath;}
QRectF boundingRect() const {return _painterPath.boundingRect();}

View File

@ -250,7 +250,7 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
MapItem *MapView::addMap(MapAction *map)
{
MapItem *mi = new MapItem(map, _map, _inputProjection);
MapItem *mi = new MapItem(map, _map);
mi->setColor(_palette.nextColor());
mi->setWidth(_areaWidth);
mi->setPenStyle(_areaStyle);
@ -331,7 +331,7 @@ int MapView::fitMapZoom() const
RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? _map->llBounds(_inputProjection) : br);
br.isNull() ? _map->llBounds() : br);
}
QPointF MapView::contentCenter() const

View File

@ -98,6 +98,7 @@ public:
void fitContentToSize();
RectC boundingRect() const;
const Projection &inputProjection() const {return _inputProjection;}
#ifdef Q_OS_ANDROID
signals:

View File

@ -11,6 +11,7 @@
#define CATTRK 54
#define CATREA 56
#define CATSIT 61
#define CATSIL 63
#define CATSCF 65
#define CATWAT 69
#define CATWRK 71

View File

@ -28,12 +28,23 @@ struct DR {
char FieldTagSize;
};
const QVariant *ISO8211::Field::data(const QByteArray &name, int idx) const
{
const QVector<QVariant> &v = _data.at(idx);
for (int i = 0; i < _subFields.size(); i++)
if (_subFields.at(i) == name)
return &v.at(i);
return 0;
}
bool ISO8211::Field::subfield(const char *name, int *val, int idx) const
{
const QVariant *v;
bool ok;
v = data().field(name, idx);
const QVariant *v = data(name, idx);
if (!v)
return false;
*val = v->toInt(&ok);
@ -43,10 +54,9 @@ bool ISO8211::Field::subfield(const char *name, int *val, int idx) const
bool ISO8211::Field::subfield(const char *name, uint *val, int idx) const
{
const QVariant *v;
bool ok;
v = data().field(name, idx);
const QVariant *v = data(name, idx);
if (!v)
return false;
*val = v->toUInt(&ok);
@ -56,9 +66,7 @@ bool ISO8211::Field::subfield(const char *name, uint *val, int idx) const
bool ISO8211::Field::subfield(const char *name, QByteArray *val, int idx) const
{
const QVariant *v;
v = data().field(name, idx);
const QVariant *v = data(name, idx);
if (!v)
return false;
*val = v->toByteArray();
@ -66,25 +74,24 @@ bool ISO8211::Field::subfield(const char *name, QByteArray *val, int idx) const
return true;
}
ISO8211::SubFieldDefinition ISO8211::fieldType(const QString &str, int cnt,
const QByteArray &tag)
ISO8211::SubFieldDefinition ISO8211::fieldType(const QString &str, int cnt)
{
if (str == "A" || str == "I" || str == "R")
return SubFieldDefinition(tag, String, cnt);
return SubFieldDefinition(String, cnt);
else if (str == "B")
return SubFieldDefinition(tag, Array, cnt / 8);
return SubFieldDefinition(Array, cnt / 8);
else if (str == "b11")
return SubFieldDefinition(tag, U8, 1);
return SubFieldDefinition(U8, 1);
else if (str == "b12")
return SubFieldDefinition(tag, U16, 2);
return SubFieldDefinition(U16, 2);
else if (str == "b14")
return SubFieldDefinition(tag, U32, 4);
return SubFieldDefinition(U32, 4);
else if (str == "b21")
return SubFieldDefinition(tag, S8, 1);
return SubFieldDefinition(S8, 1);
else if (str == "b22")
return SubFieldDefinition(tag, S16, 2);
return SubFieldDefinition(S16, 2);
else if (str == "b24")
return SubFieldDefinition(tag, S32, 4);
return SubFieldDefinition(S32, 4);
else
return SubFieldDefinition();
}
@ -138,6 +145,7 @@ bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
QByteArray ba;
bool repeat = false;
QVector<SubFieldDefinition> defs;
QVector<QByteArray> defTags;
ba.resize(def.size);
if (!(_file.seek(def.pos) && _file.read(ba.data(), ba.size()) == ba.size()))
@ -155,6 +163,7 @@ bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
int tag = 0;
defs.resize(tags.size());
defTags.resize(tags.size());
while (it.hasNext()) {
QRegularExpressionMatch match = it.next();
@ -176,16 +185,17 @@ bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
}
for (uint i = 0; i < cnt; i++) {
SubFieldDefinition sfd(fieldType(typeStr, size, tags.at(tag)));
SubFieldDefinition sfd(fieldType(typeStr, size));
if (sfd.type() == Unknown)
return false;
defs[tag] = sfd;
defTags[tag] = tags.at(tag);
tag++;
}
}
}
fields = SubFields(defs, repeat);
fields = SubFields(defTags, defs, repeat);
return true;
}
@ -223,7 +233,8 @@ bool ISO8211::readDDR()
return true;
}
bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def, Data &data)
bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
const QVector<SubFieldDefinition> &fields, bool repeat, Data &data)
{
QByteArray ba;
@ -238,10 +249,10 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def, Data &data)
do {
QVector<QVariant> row;
row.resize(data.fields()->size());
row.resize(fields.size());
for (int i = 0; i < data.fields()->size(); i++) {
const SubFieldDefinition &f = data.fields()->at(i);
for (int i = 0; i < fields.size(); i++) {
const SubFieldDefinition &f = fields.at(i);
switch (f.type()) {
case String:
@ -287,7 +298,7 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def, Data &data)
}
data.append(row);
} while (data.fields()->repeat() && dp < ep);
} while (repeat && dp < ep);
return true;
}
@ -299,9 +310,9 @@ bool ISO8211::readRecord(Record &record)
QVector<FieldDefinition> fields;
qint64 pos = _file.pos();
int len = readDR(fields);
if (len < 0) {
if (readDR(fields) < 0) {
_errorString = "Error reading DR";
return false;
}
@ -310,6 +321,7 @@ bool ISO8211::readRecord(Record &record)
for (int i = 0; i < fields.size(); i++) {
const FieldDefinition &def = fields.at(i);
Data data;
FieldsMap::const_iterator it = _map.find(def.tag);
if (it == _map.constEnd()) {
@ -317,15 +329,13 @@ bool ISO8211::readRecord(Record &record)
return false;
}
Data data(&it.value());
if (!readUDA(pos, def, data)) {
if (!readUDA(pos, def, it->defs(), it->repeat(), data)) {
_errorString = QString("Error reading %1 record")
.arg(QString(def.tag));
return false;
}
record[i] = Field(def.tag, data);
record[i] = Field(def.tag, it->tags(), data);
}
return true;

View File

@ -17,87 +17,17 @@ namespace ENC {
class ISO8211
{
public:
enum FieldType {Unknown, String, Array, S8, S16, S32, U8, U16, U32};
struct FieldDefinition
{
QByteArray tag;
int pos;
int size;
};
class SubFieldDefinition
{
public:
SubFieldDefinition() : _type(Unknown), _size(0) {}
SubFieldDefinition(const QByteArray &tag, FieldType type, int size)
: _tag(tag), _type(type), _size(size) {}
const QByteArray &tag() const {return _tag;}
FieldType type() const {return _type;}
int size() const {return _size;}
private:
QByteArray _tag;
FieldType _type;
int _size;
};
class SubFields
{
public:
SubFields() : _repeat(false) {}
SubFields(const QVector<SubFieldDefinition> &defs, bool repeat)
: _defs(defs), _repeat(repeat) {}
int size() const {return _defs.size();}
const SubFieldDefinition &at(int i) const {return _defs.at(i);}
bool repeat() const {return _repeat;}
private:
QVector<SubFieldDefinition> _defs;
bool _repeat;
};
class Data
{
public:
Data() : _fields(0) {}
Data(const SubFields *fields) : _fields(fields) {}
int size() const {return _data.size();}
const QVector<QVariant> &at(int i) const {return _data.at(i);}
const SubFields *fields() const {return _fields;}
const QVariant *field(const QByteArray &name, int idx = 0) const
{
const QVector<QVariant> &v = _data.at(idx);
for (int i = 0; i < _fields->size(); i++)
if (_fields->at(i).tag() == name)
return &v.at(i);
return 0;
}
private:
friend class ISO8211;
void append(QVector<QVariant> &row) {_data.append(row);}
QVector<QVector<QVariant> > _data;
const SubFields *_fields;
};
typedef QVector<QVector<QVariant> > Data;
class Field
{
public:
Field() {}
Field(const QByteArray &tag, const Data &data)
: _tag(tag), _data(data) {}
Field(const QByteArray &tag, const QVector<QByteArray> &subFields,
const Data &data) : _tag(tag), _subFields(subFields), _data(data) {}
const QByteArray &tag() const {return _tag;}
const QVector<QByteArray> subFields() const {return _subFields;}
const Data &data() const {return _data;}
bool subfield(const char *name, int *val, int idx = 0) const;
@ -105,7 +35,10 @@ public:
bool subfield(const char *name, QByteArray *val, int idx = 0) const;
private:
const QVariant *data(const QByteArray &name, int idx = 0) const;
QByteArray _tag;
QVector<QByteArray> _subFields;
Data _data;
};
@ -120,14 +53,57 @@ public:
static const Field *field(const Record &record, const QByteArray &name);
private:
enum FieldType {Unknown, String, Array, S8, S16, S32, U8, U16, U32};
struct FieldDefinition
{
QByteArray tag;
int pos;
int size;
};
class SubFieldDefinition
{
public:
SubFieldDefinition() : _type(Unknown), _size(0) {}
SubFieldDefinition(FieldType type, int size)
: _type(type), _size(size) {}
FieldType type() const {return _type;}
int size() const {return _size;}
private:
FieldType _type;
int _size;
};
class SubFields
{
public:
SubFields() : _repeat(false) {}
SubFields(const QVector<QByteArray> &tags,
const QVector<SubFieldDefinition> &defs, bool repeat)
: _tags(tags), _defs(defs), _repeat(repeat) {}
const QVector<QByteArray> &tags() const {return _tags;}
const QVector<SubFieldDefinition> &defs() const {return _defs;}
bool repeat() const {return _repeat;}
private:
QVector<QByteArray> _tags;
QVector<SubFieldDefinition> _defs;
bool _repeat;
};
typedef QMap<QByteArray, SubFields> FieldsMap;
static SubFieldDefinition fieldType(const QString &str, int cnt,
const QByteArray &tag);
static SubFieldDefinition fieldType(const QString &str, int cnt);
int readDR(QVector<FieldDefinition> &fields);
bool readDDA(const FieldDefinition &def, SubFields &fields);
bool readUDA(quint64 pos, const FieldDefinition &def, Data &data);
bool readUDA(quint64 pos, const FieldDefinition &def,
const QVector<SubFieldDefinition> &fields, bool repeat, Data &data);
QFile _file;
FieldsMap _map;
@ -135,22 +111,9 @@ private:
};
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const ISO8211::FieldDefinition &def)
{
dbg.nospace() << "FieldDefinition(" << def.tag << ", " << def.size << ")";
return dbg.space();
}
inline QDebug operator<<(QDebug dbg, const ISO8211::SubFieldDefinition &def)
{
dbg.nospace() << "SubField(" << def.tag() << ", " << def.type() << ", "
<< def.size() << ")";
return dbg.space();
}
inline QDebug operator<<(QDebug dbg, const ISO8211::Field &field)
{
dbg.nospace() << "Field(" << field.tag() << ")";
dbg.nospace() << "Field(" << field.tag() << ", " << field.subFields() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -560,7 +560,8 @@ MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL)
|| (OBJL == SISTAT && key == CATSIT)
|| (OBJL == I_SISTAT && key == I_CATSIT)
|| (OBJL == RDOCAL && key == TRAFIC)
|| (OBJL == I_RDOCAL && key == TRAFIC))
|| (OBJL == I_RDOCAL && key == TRAFIC)
|| (OBJL == SILTNK && key == CATSIL))
subtype = av.at(1).toByteArray().toUInt();
else if (OBJL == I_DISMAR && key == CATDIS)
subtype |= av.at(1).toByteArray().toUInt();

View File

@ -25,6 +25,7 @@
#define CANALS 23
#define CGUSTA 29
#define COALNE 30
#define CONZNE 31
#define CONVYR 34
#define CRANES 35
#define CURENT 36

View File

@ -104,6 +104,8 @@ void Style::polygonStyle()
_polygons[SUBTYPE(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[SUBTYPE(I_BERTHS, 6)] = Polygon(Qt::NoBrush, QPen(QColor("#eb49eb"),
1, Qt::DashLine));
_polygons[TYPE(CONZNE)] = Polygon(Qt::NoBrush, QPen(QColor("#eb49eb"), 1,
Qt::DashDotLine));
_drawOrder
<< TYPE(M_COVR) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0)
@ -122,7 +124,7 @@ void Style::polygonStyle()
<< SUBTYPE(RESARE, 9) << SUBTYPE(RESARE, 2) << SUBTYPE(I_RESARE, 2)
<< SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 12)
<< SUBTYPE(I_RESARE, 12) << SUBTYPE(RESARE, 1) << TYPE(CBLARE)
<< TYPE(PIPARE) << TYPE(PRCARE) << SUBTYPE(MARKUL, 3);
<< TYPE(PIPARE) << TYPE(PRCARE) << SUBTYPE(MARKUL, 3) << TYPE(CONZNE);
}
void Style::lineStyle()
@ -254,7 +256,11 @@ void Style::pointStyle()
_points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png"));
_points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png"));
_points[TYPE(RTPBCN)] = Point(QImage(":/marine/radar-transponder.png"));
_points[TYPE(SILTNK)] = Point(QImage(":/marine/silo.png"));
_points[SUBTYPE(SILTNK, 0)] = Point(QImage(":/marine/silo.png"));
_points[SUBTYPE(SILTNK, 1)] = Point(QImage(":/marine/silo.png"));
_points[SUBTYPE(SILTNK, 2)] = Point(QImage(":/marine/tank.png"));
_points[SUBTYPE(SILTNK, 3)] = Point(QImage(":/marine/silo.png"));
_points[SUBTYPE(SILTNK, 4)] = Point(QImage(":/marine/silo.png"));
_points[TYPE(I_TRNBSN)] = Point(QImage(":/marine/turning-basin.png"));
_points[TYPE(I_TRNBSN)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_WTWGAG)] = Point(QImage(":/marine/gauge.png"), Small);

View File

@ -405,8 +405,10 @@ void AQMMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp)
painter->drawPixmap(tp, pixmap);
}
Map *AQMMap::create(const QString &path, bool *isDir)
Map *AQMMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -17,7 +17,7 @@ public:
QString name() const {return _name;}
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}
@ -38,7 +38,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
struct File {

View File

@ -7,7 +7,7 @@
#include "atlas.h"
#define ZOOM_THRESHOLD 0.9
#define ZOOM_THRESHOLD 0.8
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
@ -27,6 +27,34 @@ static bool yCmp(OziMap *m1, OziMap *m2)
return TL(m1).y() > TL(m2).y();
}
static QString calibrationFile(const QString &path)
{
QDir dir(path);
QFileInfoList files = dir.entryInfoList(QDir::Files);
for (int i = 0; i < files.size(); i++) {
const QFileInfo &fi = files.at(i);
QString suffix(fi.suffix().toLower());
if (suffix == "map" || suffix == "gmi")
return fi.absoluteFilePath();
}
return QString();
}
static QString tbaFile(const QStringList &files)
{
for (int i = 0; i < files.size(); i++) {
QFileInfo fi(files.at(i));
if (fi.path() == "." && fi.suffix().toLower() == "tba")
return files.at(i);
}
return QString();
}
void Atlas::computeZooms()
{
std::sort(_maps.begin(), _maps.end(), resCmp);
@ -72,8 +100,9 @@ void Atlas::computeBounds()
QRectF(offsets.at(i), _maps.at(i)->bounds().size()));
}
Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _valid(false)
Atlas::Atlas(const QString &fileName, bool TAR, const Projection &proj,
QObject *parent) : Map(fileName, parent), _zoom(0), _mapIndex(-1),
_valid(false)
{
QFileInfo fi(fileName);
QByteArray ba;
@ -86,7 +115,11 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
_errorString = "Error reading tar file";
return;
}
QString tbaFileName = fi.completeBaseName() + ".tba";
QString tbaFileName(tbaFile(tar.files()));
if (tbaFileName.isNull()) {
_errorString = "No tba file found";
return;
}
ba = tar.file(tbaFileName);
} else {
QFile tbaFile(fileName);
@ -97,7 +130,7 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
ba = tbaFile.readAll();
}
if (!ba.startsWith("Atlas 1.0")) {
_errorString = "Missing or invalid tba file";
_errorString = "Invalid tba file";
return;
}
@ -108,38 +141,41 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
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;
if (tar.isOpen())
map = new OziMap(mapFile, tar, this);
else
map = new OziMap(mapFile, TAR, this);
if (TAR)
map = new OziMap(maps.at(i).absoluteFilePath(), tar, proj, this);
else {
QString cf(calibrationFile(maps.at(i).absoluteFilePath()));
if (cf.isNull()) {
_errorString = "No calibration file found";
return;
}
map = new OziMap(cf, proj, this);
}
if (map->isValid())
_maps.append(map);
else {
_errorString = QString("Error loading map: %1: %2")
.arg(mapFile, map->errorString());
return;
qWarning("%s: %s", qPrintable(map->path()),
qPrintable(map->errorString()));
delete map;
}
}
}
if (_maps.isEmpty()) {
_errorString = "No maps found in atlas";
_errorString = "No usable map found in atlas";
return;
}
_valid = true;
}
RectC Atlas::llBounds(const Projection &proj)
RectC Atlas::llBounds()
{
RectC bounds;
for (int i = 0; i < _maps.size(); i++)
bounds |= _maps.at(i)->llBounds(proj);
bounds |= _maps.at(i)->llBounds();
return bounds;
}
@ -295,18 +331,34 @@ void Atlas::unload()
_bounds.clear();
}
Map *Atlas::createTAR(const QString &path, bool *isDir)
Map *Atlas::createTAR(const QString &path, const Projection &proj, bool *isDir)
{
if (isDir)
*isDir = true;
return new Atlas(path, true);
return new Atlas(path, true, proj);
}
Map *Atlas::createTBA(const QString &path, bool *isDir)
Map *Atlas::createTBA(const QString &path, const Projection &proj, bool *isDir)
{
if (isDir)
*isDir = true;
return new Atlas(path, false);
return new Atlas(path, false, proj);
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Atlas::Bounds &bounds)
{
dbg.nospace() << "Bounds(" << bounds.xy << ", " << bounds.pp << ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const Atlas::Zoom &zoom)
{
dbg.nospace() << "Zoom(" << zoom.first << ", " << zoom.last << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -12,12 +12,13 @@ class Atlas : public Map
Q_OBJECT
public:
Atlas(const QString &fileName, bool TAR, QObject *parent = 0);
Atlas(const QString &fileName, bool TAR, const Projection &proj,
QObject *parent = 0);
QString name() const {return _name;}
QRectF bounds();
RectC llBounds(const Projection &proj);
RectC llBounds();
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -37,8 +38,10 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *createTAR(const QString &path, bool *isDir);
static Map *createTBA(const QString &path, bool *isDir);
static Map *createTAR(const QString &path, const Projection &proj,
bool *isDir);
static Map *createTBA(const QString &path, const Projection &proj,
bool *isDir);
private:
struct Zoom {
@ -61,6 +64,9 @@ private:
void computeZooms();
void computeBounds();
friend QDebug operator<<(QDebug dbg, const Bounds &bounds);
friend QDebug operator<<(QDebug dbg, const Zoom &zoom);
QString _name;
QList<OziMap*> _maps;
@ -73,4 +79,9 @@ private:
QString _errorString;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Atlas::Zoom &zoom);
QDebug operator<<(QDebug dbg, const Atlas::Bounds &bounds);
#endif // QT_NO_DEBUG
#endif // ATLAS_H

View File

@ -462,8 +462,10 @@ void BSBMap::unload()
_img = 0;
}
Map *BSBMap::create(const QString &path, bool *isMap)
Map *BSBMap::create(const QString &path, const Projection &proj, bool *isMap)
{
Q_UNUSED(proj);
if (isMap)
*isMap = false;

View File

@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isMap);
static Map *create(const QString &path, const Projection &proj, bool *isMap);
private:
bool parseBSB(const QByteArray &line);

View File

@ -378,8 +378,10 @@ void ENCAtlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map *ENCAtlas::create(const QString &path, bool *isDir)
Map *ENCAtlas::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = true;

View File

@ -22,7 +22,7 @@ public:
QString name() const {return _name;}
QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;}
RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -44,7 +44,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private slots:
void jobFinished(ENCJob *job);

View File

@ -345,8 +345,10 @@ void ENCMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map *ENCMap::create(const QString &path, bool *isMap)
Map *ENCMap::create(const QString &path, const Projection &proj, bool *isMap)
{
Q_UNUSED(proj);
if (isMap)
*isMap = false;

View File

@ -23,7 +23,7 @@ public:
QString name() const {return _name;}
QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;}
RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -45,7 +45,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isMap);
static Map *create(const QString &path, const Projection &proj, bool *isMap);
private slots:
void jobFinished(ENCJob *job);

View File

@ -301,8 +301,10 @@ void GEMFMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp)
painter->drawPixmap(tp, pixmap);
}
Map *GEMFMap::create(const QString &path, bool *isDir)
Map *GEMFMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -14,7 +14,7 @@ public:
GEMFMap(const QString &fileName, QObject *parent = 0);
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
int zoom() const {return _zi;}
void setZoom(int zoom) {_zi = zoom;}
@ -35,7 +35,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
struct Region {

View File

@ -73,8 +73,10 @@ void GeoTIFFMap::unload()
_img = 0;
}
Map *GeoTIFFMap::create(const QString &path, bool *isDir)
Map *GeoTIFFMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -29,7 +29,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
Projection _projection;

74
src/map/gmifile.cpp Normal file
View File

@ -0,0 +1,74 @@
#include <QIODevice>
#include "gmifile.h"
static CalibrationPoint calibrationPoint(const QByteArray line)
{
bool xOk, yOk, lonOk, latOk;
QList<QByteArray> list = line.split(';');
if (list.size() != 4)
return CalibrationPoint();
int x = list.at(0).toInt(&xOk);
int y = list.at(1).toInt(&yOk);
double lon = list.at(2).toDouble(&lonOk);
double lat = list.at(3).toDouble(&latOk);
return (xOk && yOk && latOk && lonOk)
? CalibrationPoint(PointD(x, y), Coordinates(lon, lat))
: CalibrationPoint();
}
bool GmiFile::parse(QIODevice &device)
{
int ln = 1;
int width, height;
bool ok;
if (!device.open(QIODevice::ReadOnly)) {
_errorString = device.errorString();
return false;
}
while (!device.atEnd()) {
QByteArray line = device.readLine(4096);
if (ln == 1) {
if (!line.startsWith("Map Calibration data file")) {
_errorString = "Not a GMI file";
return false;
}
} else if (ln == 2)
_image = line.trimmed();
else if (ln == 3) {
width = line.toInt(&ok);
if (!ok || ok <= 0) {
_errorString = "Invalid image width";
return false;
}
} else if (ln == 4) {
height = line.toInt(&ok);
if (!ok || ok <= 0) {
_errorString = "Invalid image height";
return false;
}
_size = QSize(width, height);
} else {
CalibrationPoint cp(calibrationPoint(line));
if (cp.isValid())
_points.append(cp);
else
break;
}
ln++;
}
device.close();
return (_points.size() >= 2);
}
GmiFile::GmiFile(QIODevice &file)
{
_valid = parse(file);
}

31
src/map/gmifile.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef GMIFILE_H
#define GMIFILE_H
#include "calibrationpoint.h"
class QIODevice;
class GmiFile
{
public:
GmiFile(QIODevice &file);
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
const QString &image() const {return _image;}
const QSize &size() const {return _size;}
const QList<CalibrationPoint> &calibrationPoints() const {return _points;}
private:
bool parse(QIODevice &device);
QString _image;
QSize _size;
QList<CalibrationPoint> _points;
bool _valid;
QString _errorString;
};
#endif // GMIFILE_H

View File

@ -264,16 +264,20 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map* IMGMap::createIMG(const QString &path, bool *isDir)
Map* IMGMap::createIMG(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;
return new IMGMap(path, false);
}
Map* IMGMap::createGMAP(const QString &path, bool *isDir)
Map* IMGMap::createGMAP(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = true;

View File

@ -55,7 +55,7 @@ public:
QString name() const {return _data.first()->name();}
QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _data.first()->bounds();}
RectC llBounds() {return _data.first()->bounds();}
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -77,8 +77,10 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map* createIMG(const QString &path, bool *isDir);
static Map* createGMAP(const QString &path, bool *isDir);
static Map* createIMG(const QString &path, const Projection &proj,
bool *isDir);
static Map* createGMAP(const QString &path, const Projection &proj,
bool *isDir);
private slots:
void jobFinished(IMGMapJob *job);

View File

@ -274,8 +274,10 @@ void JNXMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
tree.Search(min, max, cb, &ctx);
}
Map *JNXMap::create(const QString &path, bool *isDir)
Map *JNXMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -19,7 +19,7 @@ public:
~JNXMap();
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
int zoom() const {return _zoom;}
void setZoom(int zoom) {_zoom = zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
struct Tile {

View File

@ -484,8 +484,10 @@ void KMZMap::draw(QPainter *painter, const QRectF &rect, int mapIndex)
painter->restore();
}
Map *KMZMap::create(const QString &path, bool *isDir)
Map *KMZMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -18,7 +18,7 @@ public:
KMZMap(const QString &fileName, QObject *parent = 0);
~KMZMap();
RectC llBounds(const Projection &) {return _llbounds;}
RectC llBounds() {return _llbounds;}
QRectF bounds();
int zoom() const {return _zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
class Overlay {

View File

@ -4,6 +4,7 @@
#define SAMPLES 100
#define DELTA 1e-6
static void growLeft(const Coordinates &c, RectC &rect)
{
@ -29,12 +30,8 @@ static void growBottom(const Coordinates &c, RectC &rect)
rect.setBottom(c.lat());
}
RectC Map::llBounds(const Projection &proj)
RectC Map::llBounds()
{
Q_UNUSED(proj);
/* We use bounds() and xy2ll() here as this fallback implementation is
used ONLY for maps providing those functions since map creation. */
QRectF b(bounds());
double dx = b.width() / SAMPLES;
double dy = b.height() / SAMPLES;
@ -55,14 +52,27 @@ RectC Map::llBounds(const Projection &proj)
growRight(xy2ll(QPointF(b.right(), y)), rect);
}
if (rect.right() <= -180.0 + DELTA)
rect.setRight(180.0);
if (rect.left() >= 180.0 - DELTA)
rect.setLeft(-180.0);
return rect;
}
qreal Map::resolution(const QRectF &rect)
{
qreal cy = rect.center().y();
QPointF cl(rect.left(), cy);
QPointF cr(rect.right(), cy);
/* The haversine formula used in Coordinates::distanceTo() only gives
"half world" distances and shorter so we have to use only the center
"half rectangle" in case e.g. world map bounds are on the input */
QRectF halfRect(QPointF(rect.left() + (rect.width() / 4.0),
rect.top() + (rect.height() / 4.0)),
QPointF(rect.right() - (rect.width() / 4.0),
rect.bottom() - (rect.height() / 4.0)));
qreal cy = halfRect.center().y();
QPointF cl(halfRect.left(), cy);
QPointF cr(halfRect.right(), cy);
qreal ds = xy2ll(cl).distanceTo(xy2ll(cr));
qreal ps = QLineF(cl, cr).length();

View File

@ -28,19 +28,19 @@ public:
: QObject(parent), _path(path) {}
virtual ~Map() {}
/* Functions available since map creation */
const QString &path() const {return _path;}
virtual QString name() const {return Util::file2name(path());}
virtual RectC llBounds(const Projection &proj);
virtual bool isValid() const {return true;}
virtual bool isReady() const {return true;}
virtual QString errorString() const {return QString();}
/* Functions that shall be called after load() */
virtual void load(const Projection &, const Projection &, qreal, bool) {}
virtual void unload() {}
/* llBounds() is mandatory for maps that do not provide bounds() until
load() is called! */
virtual RectC llBounds();
virtual QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect);

View File

@ -43,6 +43,7 @@ MapList::ParserMap MapList::parsers()
map.insert("rtmap", &RMap::create);
map.insert("map", &MapsforgeMap::create);
map.insert("map", &OziMap::createMAP);
map.insert("gmi", &OziMap::createMAP);
map.insert("kap", &BSBMap::create);
map.insert("kmz", &KMZMap::create);
map.insert("aqm", &AQMMap::create);
@ -64,7 +65,7 @@ MapList::ParserMap MapList::parsers()
MapList::ParserMap MapList::_parsers = parsers();
Map *MapList::loadFile(const QString &path, bool *isDir)
Map *MapList::loadFile(const QString &path, const Projection &proj, bool *isDir)
{
ParserMap::iterator it;
QFileInfo fi(Util::displayName(path));
@ -75,7 +76,7 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
if ((it = _parsers.find(suffix)) != _parsers.end()) {
while (it != _parsers.end() && it.key() == suffix) {
delete map;
map = it.value()(path, isDir);
map = it.value()(path, proj, isDir);
if (map->isValid())
return map;
else
@ -84,7 +85,7 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
}
} else {
for (it = _parsers.begin(); it != _parsers.end(); it++) {
map = it.value()(path, isDir);
map = it.value()(path, proj, isDir);
if (map->isValid())
return map;
else {
@ -102,7 +103,8 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
return map ? map : new InvalidMap(path, "Unknown file format");
}
TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent)
TreeNode<Map*> MapList::loadDir(const QString &path, const Projection &proj,
TreeNode<Map*> *parent)
{
QDir md(path);
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
@ -119,12 +121,12 @@ TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent)
QString suffix = fi.suffix().toLower();
if (fi.isDir()) {
TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), &tree));
TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), proj, &tree));
if (!child.isEmpty())
tree.addChild(child);
} else if (filter().contains("*." + suffix)) {
bool isDir = false;
Map *map = loadFile(fi.absoluteFilePath(), &isDir);
Map *map = loadFile(fi.absoluteFilePath(), proj, &isDir);
if (isDir) {
if (parent)
parent->addItem(map);
@ -139,13 +141,13 @@ TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent)
return tree;
}
TreeNode<Map *> MapList::loadMaps(const QString &path)
TreeNode<Map *> MapList::loadMaps(const QString &path, const Projection &proj)
{
if (QFileInfo(path).isDir())
return loadDir(path);
return loadDir(path, proj);
else {
TreeNode<Map*> tree;
tree.addItem(loadFile(path));
tree.addItem(loadFile(path, proj));
return tree;
}
}
@ -173,7 +175,8 @@ QString MapList::formats()
+ qApp->translate("MapList", "Osmdroid SQLite maps") + " (*.sqlite);;"
+ qApp->translate("MapList", "Locus/OsmAnd/RMaps SQLite maps")
+ " (*.sqlitedb);;"
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
+ qApp->translate("MapList", "TrekBuddy maps/atlases")
+ " (*.tar *.tba *.gmi *.map);;"
+ qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;"
+ qApp->translate("MapList", "World-file georeferenced images")
+ " (*.wld *.jgw *.gfw *.pgw *.tfw);;"

View File

@ -10,16 +10,18 @@ class Projection;
class MapList
{
public:
static TreeNode<Map*> loadMaps(const QString &path);
static TreeNode<Map*> loadMaps(const QString &path, const Projection &proj);
static QString formats();
static QStringList filter();
private:
typedef Map*(*ParserCb)(const QString &, bool *isDir);
typedef Map*(*ParserCb)(const QString &, const Projection &, bool *);
typedef QMultiMap<QString, ParserCb> ParserMap;
static Map *loadFile(const QString &path, bool *isDir = 0);
static TreeNode<Map*> loadDir(const QString &path, TreeNode<Map*> *parent = 0);
static Map *loadFile(const QString &path, const Projection &proj,
bool *isDir = 0);
static TreeNode<Map*> loadDir(const QString &path, const Projection &proj,
TreeNode<Map*> *parent = 0);
static ParserMap parsers();
static ParserMap _parsers;

View File

@ -209,8 +209,11 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map *MapsforgeMap::create(const QString &path, bool *isMap)
Map *MapsforgeMap::create(const QString &path, const Projection &proj,
bool *isMap)
{
Q_UNUSED(proj);
if (isMap)
*isMap = false;

View File

@ -52,7 +52,7 @@ public:
MapsforgeMap(const QString &fileName, QObject *parent = 0);
QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _data.bounds();}
RectC llBounds() {return _data.bounds();}
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -74,7 +74,7 @@ public:
bool isValid() const {return _data.isValid();}
QString errorString() const {return _data.errorString();}
static Map *create(const QString &path, bool *isMap);
static Map *create(const QString &path, const Projection &proj, bool *isMap);
private slots:
void jobFinished(MapsforgeMapJob *job);

View File

@ -214,8 +214,9 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
}
}
Map *MapSource::create(const QString &path, bool *isDir)
Map *MapSource::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
Config config;
QFile file(path);

View File

@ -15,7 +15,7 @@ class Projection;
class MapSource
{
public:
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
enum Type {

View File

@ -338,8 +338,10 @@ Coordinates MBTilesMap::xy2ll(const QPointF &p)
* coordinatesRatio());
}
Map *MBTilesMap::create(const QString &path, bool *isDir)
Map *MBTilesMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -13,7 +13,7 @@ public:
QString name() const {return _name;}
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zi;}
@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
qreal tileSize() const;

View File

@ -590,8 +590,10 @@ Coordinates OruxMap::xy2ll(const QPointF &p)
return z.projection.xy2ll(z.transform.img2proj(p * _mapRatio));
}
Map *OruxMap::create(const QString &path, bool *isDir)
Map *OruxMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = true;

View File

@ -40,7 +40,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
struct Zoom {

View File

@ -309,8 +309,11 @@ Coordinates OsmdroidMap::xy2ll(const QPointF &p)
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio);
}
Map *OsmdroidMap::create(const QString &path, bool *isDir)
Map *OsmdroidMap::create(const QString &path, const Projection &proj,
bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -11,7 +11,7 @@ public:
OsmdroidMap(const QString &fileName, QObject *parent = 0);
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
int limitZoom(int zoom) const;

View File

@ -12,58 +12,135 @@
#include "ozf.h"
#include "image.h"
#include "mapfile.h"
#include "gmifile.h"
#include "rectd.h"
#include "ozimap.h"
OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
static QString tarFile(const QString &path)
{
QDir dir(path);
QFileInfoList files = dir.entryInfoList(QDir::Files);
for (int i = 0; i < files.size(); i++) {
const QFileInfo &fi = files.at(i);
if (fi.suffix().toLower() == "tar")
return fi.absoluteFilePath();
}
return QString();
}
QString OziMap::calibrationFile(const QStringList &files, const QString path,
CalibrationType &type)
{
for (int i = 0; i < files.size(); i++) {
QFileInfo fi(files.at(i));
QString suffix(fi.suffix().toLower());
if (path.endsWith(fi.path())) {
if (suffix == "map") {
type = MAP;
return files.at(i);
} else if (suffix == "gmi") {
type = GMI;
return files.at(i);
}
}
}
type = Unknown;
return QString();
}
OziMap::OziMap(const QString &fileName, const Projection &proj, QObject *parent)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false)
{
QFileInfo fi(fileName);
QString suffix(fi.suffix().toLower());
if (suffix == "tar") {
CalibrationType type;
if (TAR) {
_tar = new Tar(fileName);
if (!_tar->open()) {
_errorString = "Error reading tar file";
return;
}
QStringList files(_tar->files());
QString cf(calibrationFile(files, ".", type));
QString mapFileName = fi.completeBaseName() + ".map";
QByteArray ba = _tar->file(mapFileName);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
if (type == GMI) {
QByteArray ba(_tar->file(cf));
QBuffer buffer(&ba);
GmiFile gmi(buffer);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
} else {
_name = Util::file2name(fileName);
_map.size = gmi.size();
_map.path = gmi.image();
_calibrationPoints = gmi.calibrationPoints();
_projection = proj;
computeTransform();
}
} else if (type == MAP) {
QByteArray ba(_tar->file(cf));
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
_errorString = "No calibration file found";
return;
}
if (!setTileInfo(_tar->files()))
if (!setTileInfo(files))
return;
_tar->close();
} else {
QFile file(fileName);
MapFile mf(file);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
if (suffix == "map") {
MapFile mf(file);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "gmi") {
GmiFile gmi(file);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
} else {
_name = Util::file2name(fileName);
_map.size = gmi.size();
_map.path = gmi.image();
_calibrationPoints = gmi.calibrationPoints();
_projection = proj;
computeTransform();
}
} else {
_name = mf.name();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
_errorString = "Unknown file type";
return;
}
QDir set(fi.absolutePath() + "/" + "set");
@ -79,34 +156,51 @@ OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
_valid = true;
}
OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false)
OziMap::OziMap(const QString &dirName, Tar &tar, const Projection &proj,
QObject *parent) : Map(dirName, parent), _img(0), _tar(0), _ozf(0), _zoom(0),
_mapRatio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QFileInfo map(fi.absolutePath());
QFileInfo layer(map.absolutePath());
QString mapFile = layer.fileName() + "/" + map.fileName() + "/"
+ fi.fileName();
CalibrationType type;
QString cf(calibrationFile(tar.files(), dirName, type));
QByteArray ba = tar.file(mapFile);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
if (type == MAP) {
QByteArray ba = tar.file(cf);
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
}
_name = mf.name();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
} else if (type == GMI) {
QByteArray ba = tar.file(cf);
QBuffer buffer(&ba);
GmiFile gmi(buffer);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
}
_name = Util::file2name(cf);
_map.size = gmi.size();
_calibrationPoints = gmi.calibrationPoints();
_projection = proj;
computeTransform();
} else {
_errorString = "No calibration file found";
return;
}
_name = mf.name();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
QString tf(tarFile(dirName));
if (tf.isNull()) {
_errorString = "No map tar file found";
return;
}
_tar = new Tar(tf);
if (!_tar->open()) {
_errorString = _tar->fileName() + ": error reading tar file";
return;
@ -208,10 +302,13 @@ bool OziMap::setTileInfo(const QStringList &tiles, const QString &path)
void OziMap::load(const Projection &in, const Projection &out,
qreal deviceRatio, bool hidpi)
{
Q_UNUSED(in);
Q_UNUSED(out);
_mapRatio = hidpi ? deviceRatio : 1.0;
if (!_calibrationPoints.isEmpty()) {
_projection = in;
computeTransform();
}
if (_tar) {
Q_ASSERT(!_tar->isOpen());
@ -395,18 +492,28 @@ void OziMap::rescale(int zoom)
_scale = _ozf->scale(zoom);
}
Map *OziMap::createTAR(const QString &path, bool *isDir)
void OziMap::computeTransform()
{
QList<ReferencePoint> rp;
for (int i = 0; i < _calibrationPoints.size(); i++)
rp.append(_calibrationPoints.at(i).rp(_projection));
_transform = Transform(rp);
}
Map *OziMap::createTAR(const QString &path, const Projection &proj, bool *isDir)
{
if (isDir)
*isDir = false;
return new OziMap(path, true);
return new OziMap(path, proj);
}
Map *OziMap::createMAP(const QString &path, bool *isDir)
Map *OziMap::createMAP(const QString &path, const Projection &proj, bool *isDir)
{
if (isDir)
*isDir = false;
return new OziMap(path, false);
return new OziMap(path, proj);
}

View File

@ -3,6 +3,7 @@
#include "transform.h"
#include "projection.h"
#include "calibrationpoint.h"
#include "map.h"
class Tar;
@ -14,8 +15,10 @@ class OziMap : public Map
Q_OBJECT
public:
OziMap(const QString &fileName, bool TAR, QObject *parent = 0);
OziMap(const QString &fileName, Tar &tar, QObject *parent = 0);
OziMap(const QString &fileName, const Projection &proj,
QObject *parent = 0);
OziMap(const QString &dirName, Tar &tar, const Projection &proj,
QObject *parent = 0);
~OziMap();
QString name() const {return _name;}
@ -47,10 +50,16 @@ public:
QPointF pp2xy(const PointD &p) const
{return _transform.proj2img(p) / _mapRatio;}
static Map *createTAR(const QString &path, bool *isDir);
static Map *createMAP(const QString &path, bool *isDir);
static Map *createTAR(const QString &path, const Projection &proj,
bool *isDir);
static Map *createMAP(const QString &path, const Projection &proj,
bool *isDir);
private:
enum CalibrationType {
Unknown, MAP, GMI
};
struct ImageInfo {
QSize size;
QString path;
@ -66,6 +75,10 @@ private:
void drawImage(QPainter *painter, const QRectF &rect, Flags flags) const;
void rescale(int zoom);
void computeTransform();
static QString calibrationFile(const QStringList &files, const QString path,
CalibrationType &type);
QString _name;
Projection _projection;
@ -77,6 +90,7 @@ private:
int _zoom;
QPointF _scale;
qreal _mapRatio;
QList<CalibrationPoint> _calibrationPoints;
bool _valid;
QString _errorString;

View File

@ -491,8 +491,10 @@ void QCTMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map *QCTMap::create(const QString &path, bool *isDir)
Map *QCTMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -28,7 +28,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
bool readName(QDataStream &stream);

View File

@ -460,8 +460,10 @@ void RMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
Map *RMap::create(const QString &path, bool *isDir)
Map *RMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
struct Header {

View File

@ -256,8 +256,10 @@ Coordinates SqliteMap::xy2ll(const QPointF &p)
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio);
}
Map *SqliteMap::create(const QString &path, bool *isDir)
Map *SqliteMap::create(const QString &path, const Projection &proj, bool *isDir)
{
Q_UNUSED(proj);
if (isDir)
*isDir = false;

View File

@ -11,7 +11,7 @@ public:
SqliteMap(const QString &fileName, QObject *parent = 0);
QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;}
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
int limitZoom(int zoom) const;

View File

@ -6,6 +6,7 @@
#include <QtConcurrent>
#include "tileloader.h"
#define SUBSTITUTE_CHAR '$'
class TileImage
{
@ -34,6 +35,27 @@ private:
int _scaledSize;
};
static QString fsSafeStr(const QString &str)
{
QString ret(str);
#ifdef Q_OS_WIN32
ret.replace('<', SUBSTITUTE_CHAR);
ret.replace('>', SUBSTITUTE_CHAR);
ret.replace(':', SUBSTITUTE_CHAR);
ret.replace('"', SUBSTITUTE_CHAR);
ret.replace('/', SUBSTITUTE_CHAR);
ret.replace('\\', SUBSTITUTE_CHAR);
ret.replace('|', SUBSTITUTE_CHAR);
ret.replace('?', SUBSTITUTE_CHAR);
ret.replace('*', SUBSTITUTE_CHAR);
#else // Q_OS_WIN32
ret.replace('/', SUBSTITUTE_CHAR);
#endif // Q_OS_WIN32
return ret;
}
static QString quadKey(const QPoint &xy, int zoom)
{
QString qk;
@ -198,7 +220,10 @@ QUrl TileLoader::tileUrl(const FetchTile &tile) const
QString TileLoader::tileFile(const FetchTile &tile) const
{
return _dir + QLatin1Char('/') + tile.zoom().toString() + QLatin1Char('-')
QString zoom(((QMetaType::Type)(tile.zoom().type()) == QMetaType::Int)
? tile.zoom().toString() : fsSafeStr(tile.zoom().toString()));
return _dir + QLatin1Char('/') + zoom + QLatin1Char('-')
+ QString::number(tile.xy().x()) + QLatin1Char('-')
+ QString::number(tile.xy().y());
}

View File

@ -9,8 +9,9 @@
#include "worldfilemap.h"
WorldFileMap::WorldFileMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _img(0), _mapRatio(1.0), _hasPRJ(false), _valid(false)
WorldFileMap::WorldFileMap(const QString &fileName, const Projection &proj,
QObject *parent) : Map(fileName, parent), _img(0), _mapRatio(1.0),
_hasPRJ(false), _valid(false)
{
QFileInfo fi(fileName);
QDir dir(fi.absoluteDir());
@ -37,7 +38,8 @@ WorldFileMap::WorldFileMap(const QString &fileName, QObject *parent)
_errorString = prjFile + ": " + prj.errorString();
return;
}
}
} else
_projection = proj;
// Find the corresponding image file
QList<QByteArray> formats(QImageReader::supportedImageFormats());
@ -81,14 +83,6 @@ Coordinates WorldFileMap::xy2ll(const QPointF &p)
return _projection.xy2ll(_transform.img2proj(p * _mapRatio));
}
RectC WorldFileMap::llBounds(const Projection &proj)
{
if (_projection.isNull())
_projection = proj;
return Map::llBounds(proj);
}
QRectF WorldFileMap::bounds()
{
return QRectF(QPointF(0, 0), _size / _mapRatio);
@ -122,10 +116,11 @@ void WorldFileMap::unload()
_img = 0;
}
Map *WorldFileMap::create(const QString &path, bool *isDir)
Map *WorldFileMap::create(const QString &path, const Projection &proj,
bool *isDir)
{
if (isDir)
*isDir = false;
return new WorldFileMap(path);
return new WorldFileMap(path, proj);
}

View File

@ -12,10 +12,10 @@ class WorldFileMap : public Map
Q_OBJECT
public:
WorldFileMap(const QString &fileName, QObject *parent = 0);
WorldFileMap(const QString &fileName, const Projection &proj,
QObject *parent = 0);
~WorldFileMap();
RectC llBounds(const Projection &proj);
QRectF bounds();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
@ -29,7 +29,7 @@ public:
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir);
static Map *create(const QString &path, const Projection &proj, bool *isDir);
private:
Projection _projection;