1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-04 06:49:16 +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: configuration:
- Release - Release
@ -8,10 +8,13 @@ image:
environment: environment:
NSISDIR: C:\Program Files (x86)\NSIS NSISDIR: C:\Program Files (x86)\NSIS
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
matrix: matrix:
- QTDIR: C:\Qt\5.15\msvc2019_64 - QTDIR: C:\Qt\5.15\msvc2019_64
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
OPENSSLVERSION: 1_1
- QTDIR: C:\Qt\6.5\msvc2019_64 - QTDIR: C:\Qt\6.5\msvc2019_64
OPENSSLDIR: C:\OpenSSL-v30-Win64\bin
OPENSSLVERSION: 3
NSISDEF: /DQT6 NSISDEF: /DQT6
install: install:
@ -34,8 +37,8 @@ build_script:
xcopy lang\*.qm installer\translations\ /sy xcopy lang\*.qm installer\translations\ /sy
xcopy icons\symbols installer\symbols /i xcopy icons\symbols installer\symbols /i
copy licence.txt installer copy licence.txt installer
copy %OPENSSLDIR%\libcrypto-1_1-x64.dll installer copy %OPENSSLDIR%\libcrypto-%OPENSSLVERSION%-x64.dll installer
copy %OPENSSLDIR%\libssl-1_1-x64.dll installer copy %OPENSSLDIR%\libssl-%OPENSSLVERSION%-x64.dll installer
makensis.exe %NSISDEF% installer\gpxsee64.nsi makensis.exe %NSISDEF% installer\gpxsee64.nsi

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 13.8 VERSION = 13.9
QT += core \ QT += core \
@ -134,6 +134,7 @@ HEADERS += src/common/config.h \
src/map/encmap.h \ src/map/encmap.h \
src/map/ENC/iso8211.h \ src/map/ENC/iso8211.h \
src/map/gemfmap.h \ src/map/gemfmap.h \
src/map/gmifile.h \
src/map/oruxmap.h \ src/map/oruxmap.h \
src/map/osmdroidmap.h \ src/map/osmdroidmap.h \
src/map/proj/polyconic.h \ src/map/proj/polyconic.h \
@ -347,6 +348,7 @@ SOURCES += src/main.cpp \
src/map/encmap.cpp \ src/map/encmap.cpp \
src/map/ENC/iso8211.cpp \ src/map/ENC/iso8211.cpp \
src/map/gemfmap.cpp \ src/map/gemfmap.cpp \
src/map/gmifile.cpp \
src/map/oruxmap.cpp \ src/map/oruxmap.cpp \
src/map/osmdroidmap.cpp \ src/map/osmdroidmap.cpp \
src/map/proj/polyconic.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.png">icons/map/marine/radar.png</file>
<file alias="radar-transponder.png">icons/map/marine/radar-transponder.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="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="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="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> <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> <key>UTTypeIdentifier</key>
<string>int.iho.s57-catalogue</string> <string>int.iho.s57-catalogue</string>
<key>UTTypeReferenceURL</key> <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> <key>UTTypeDescription</key>
<string>IHO S-57 Electronic Navigation Catalogue</string> <string>IHO S-57 Electronic Navigation Catalogue</string>
<key>UTTypeConformsTo</key> <key>UTTypeConformsTo</key>

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "13.8" !define VERSION "13.9"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"
@ -302,8 +302,13 @@ Section "OpenSSL" SEC_OPENSSL
SectionIn RO SectionIn RO
!ifdef QT6
File "libcrypto-3-x64.dll"
File "libssl-3-x64.dll"
!else
File "libcrypto-1_1-x64.dll" File "libcrypto-1_1-x64.dll"
File "libssl-1_1-x64.dll" File "libssl-1_1-x64.dll"
!endif
SectionEnd 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) 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()); QList<QAction*> existingActions(_mapsActionGroup->actions());
return loadMapNode(maps, action, existingActions, showError); return loadMapNode(maps, action, existingActions, showError);
@ -1854,7 +1854,7 @@ void GUI::loadMapDir()
return; return;
QFileInfo fi(dir); QFileInfo fi(dir);
TreeNode<Map*> maps(MapList::loadMaps(dir)); TreeNode<Map*> maps(MapList::loadMaps(dir, _mapView->inputProjection()));
QList<QAction*> existingActions(_mapsActionGroup->actions()); QList<QAction*> existingActions(_mapsActionGroup->actions());
QList<MapAction*> actions; QList<MapAction*> actions;
QMenu *menu = new QMenu(maps.name()); QMenu *menu = new QMenu(maps.name());
@ -2985,7 +2985,7 @@ void GUI::loadInitialMaps(const QString &selected)
if (mapDir.isNull()) if (mapDir.isNull())
return; return;
TreeNode<Map*> maps(MapList::loadMaps(mapDir)); TreeNode<Map*> maps(MapList::loadMaps(mapDir, _mapView->inputProjection()));
createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd); createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd);
// Select the active map according to the user settings // Select the active map according to the user settings

View File

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

View File

@ -11,8 +11,7 @@ class MapItem : public QObject, public PlaneItem
Q_OBJECT Q_OBJECT
public: public:
MapItem(MapAction *action, Map *map, const Projection &proj, MapItem(MapAction *action, Map *map, GraphicsItem *parent = 0);
GraphicsItem *parent = 0);
QPainterPath shape() const {return _painterPath;} QPainterPath shape() const {return _painterPath;}
QRectF boundingRect() const {return _painterPath.boundingRect();} 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 *MapView::addMap(MapAction *map)
{ {
MapItem *mi = new MapItem(map, _map, _inputProjection); MapItem *mi = new MapItem(map, _map);
mi->setColor(_palette.nextColor()); mi->setColor(_palette.nextColor());
mi->setWidth(_areaWidth); mi->setWidth(_areaWidth);
mi->setPenStyle(_areaStyle); mi->setPenStyle(_areaStyle);
@ -331,7 +331,7 @@ int MapView::fitMapZoom() const
RectC br = _tr | _rr | _wr | _ar; RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN), 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 QPointF MapView::contentCenter() const

View File

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

View File

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

View File

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

View File

@ -17,87 +17,17 @@ namespace ENC {
class ISO8211 class ISO8211
{ {
public: public:
enum FieldType {Unknown, String, Array, S8, S16, S32, U8, U16, U32}; typedef QVector<QVector<QVariant> > Data;
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;
};
class Field class Field
{ {
public: public:
Field() {} Field() {}
Field(const QByteArray &tag, const Data &data) Field(const QByteArray &tag, const QVector<QByteArray> &subFields,
: _tag(tag), _data(data) {} const Data &data) : _tag(tag), _subFields(subFields), _data(data) {}
const QByteArray &tag() const {return _tag;} const QByteArray &tag() const {return _tag;}
const QVector<QByteArray> subFields() const {return _subFields;}
const Data &data() const {return _data;} const Data &data() const {return _data;}
bool subfield(const char *name, int *val, int idx = 0) const; 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; bool subfield(const char *name, QByteArray *val, int idx = 0) const;
private: private:
const QVariant *data(const QByteArray &name, int idx = 0) const;
QByteArray _tag; QByteArray _tag;
QVector<QByteArray> _subFields;
Data _data; Data _data;
}; };
@ -120,14 +53,57 @@ public:
static const Field *field(const Record &record, const QByteArray &name); static const Field *field(const Record &record, const QByteArray &name);
private: 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; typedef QMap<QByteArray, SubFields> FieldsMap;
static SubFieldDefinition fieldType(const QString &str, int cnt, static SubFieldDefinition fieldType(const QString &str, int cnt);
const QByteArray &tag);
int readDR(QVector<FieldDefinition> &fields); int readDR(QVector<FieldDefinition> &fields);
bool readDDA(const FieldDefinition &def, SubFields &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; QFile _file;
FieldsMap _map; FieldsMap _map;
@ -135,22 +111,9 @@ private:
}; };
#ifndef QT_NO_DEBUG #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) inline QDebug operator<<(QDebug dbg, const ISO8211::Field &field)
{ {
dbg.nospace() << "Field(" << field.tag() << ")"; dbg.nospace() << "Field(" << field.tag() << ", " << field.subFields() << ")";
return dbg.space(); return dbg.space();
} }
#endif // QT_NO_DEBUG #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 == SISTAT && key == CATSIT)
|| (OBJL == I_SISTAT && key == I_CATSIT) || (OBJL == I_SISTAT && key == I_CATSIT)
|| (OBJL == RDOCAL && key == TRAFIC) || (OBJL == RDOCAL && key == TRAFIC)
|| (OBJL == I_RDOCAL && key == TRAFIC)) || (OBJL == I_RDOCAL && key == TRAFIC)
|| (OBJL == SILTNK && key == CATSIL))
subtype = av.at(1).toByteArray().toUInt(); subtype = av.at(1).toByteArray().toUInt();
else if (OBJL == I_DISMAR && key == CATDIS) else if (OBJL == I_DISMAR && key == CATDIS)
subtype |= av.at(1).toByteArray().toUInt(); subtype |= av.at(1).toByteArray().toUInt();

View File

@ -25,6 +25,7 @@
#define CANALS 23 #define CANALS 23
#define CGUSTA 29 #define CGUSTA 29
#define COALNE 30 #define COALNE 30
#define CONZNE 31
#define CONVYR 34 #define CONVYR 34
#define CRANES 35 #define CRANES 35
#define CURENT 36 #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(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[SUBTYPE(I_BERTHS, 6)] = Polygon(Qt::NoBrush, QPen(QColor("#eb49eb"), _polygons[SUBTYPE(I_BERTHS, 6)] = Polygon(Qt::NoBrush, QPen(QColor("#eb49eb"),
1, Qt::DashLine)); 1, Qt::DashLine));
_polygons[TYPE(CONZNE)] = Polygon(Qt::NoBrush, QPen(QColor("#eb49eb"), 1,
Qt::DashDotLine));
_drawOrder _drawOrder
<< TYPE(M_COVR) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0) << 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, 9) << SUBTYPE(RESARE, 2) << SUBTYPE(I_RESARE, 2)
<< SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 12) << SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 12)
<< SUBTYPE(I_RESARE, 12) << SUBTYPE(RESARE, 1) << TYPE(CBLARE) << 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() void Style::lineStyle()
@ -254,7 +256,11 @@ void Style::pointStyle()
_points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png")); _points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png"));
_points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png")); _points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png"));
_points[TYPE(RTPBCN)] = Point(QImage(":/marine/radar-transponder.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)] = Point(QImage(":/marine/turning-basin.png"));
_points[TYPE(I_TRNBSN)].setTextColor(QColor("#eb49eb")); _points[TYPE(I_TRNBSN)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_WTWGAG)] = Point(QImage(":/marine/gauge.png"), Small); _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); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -17,7 +17,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -38,7 +38,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
struct File { struct File {

View File

@ -7,7 +7,7 @@
#include "atlas.h" #include "atlas.h"
#define ZOOM_THRESHOLD 0.9 #define ZOOM_THRESHOLD 0.8
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft())) #define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight())) #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(); 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() void Atlas::computeZooms()
{ {
std::sort(_maps.begin(), _maps.end(), resCmp); std::sort(_maps.begin(), _maps.end(), resCmp);
@ -72,8 +100,9 @@ void Atlas::computeBounds()
QRectF(offsets.at(i), _maps.at(i)->bounds().size())); QRectF(offsets.at(i), _maps.at(i)->bounds().size()));
} }
Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent) Atlas::Atlas(const QString &fileName, bool TAR, const Projection &proj,
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _valid(false) QObject *parent) : Map(fileName, parent), _zoom(0), _mapIndex(-1),
_valid(false)
{ {
QFileInfo fi(fileName); QFileInfo fi(fileName);
QByteArray ba; QByteArray ba;
@ -86,7 +115,11 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
_errorString = "Error reading tar file"; _errorString = "Error reading tar file";
return; return;
} }
QString tbaFileName = fi.completeBaseName() + ".tba"; QString tbaFileName(tbaFile(tar.files()));
if (tbaFileName.isNull()) {
_errorString = "No tba file found";
return;
}
ba = tar.file(tbaFileName); ba = tar.file(tbaFileName);
} else { } else {
QFile tbaFile(fileName); QFile tbaFile(fileName);
@ -97,7 +130,7 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
ba = tbaFile.readAll(); ba = tbaFile.readAll();
} }
if (!ba.startsWith("Atlas 1.0")) { if (!ba.startsWith("Atlas 1.0")) {
_errorString = "Missing or invalid tba file"; _errorString = "Invalid tba file";
return; return;
} }
@ -108,38 +141,41 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
QFileInfoList maps = zdir.entryInfoList(QDir::Dirs QFileInfoList maps = zdir.entryInfoList(QDir::Dirs
| QDir::NoDotAndDotDot); | QDir::NoDotAndDotDot);
for (int i = 0; i < maps.count(); i++) { for (int i = 0; i < maps.count(); i++) {
QString mapFile = maps.at(i).absoluteFilePath() + "/"
+ maps.at(i).fileName() + ".map";
OziMap *map; OziMap *map;
if (tar.isOpen()) if (TAR)
map = new OziMap(mapFile, tar, this); map = new OziMap(maps.at(i).absoluteFilePath(), tar, proj, this);
else else {
map = new OziMap(mapFile, TAR, this); 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()) if (map->isValid())
_maps.append(map); _maps.append(map);
else { else {
_errorString = QString("Error loading map: %1: %2") qWarning("%s: %s", qPrintable(map->path()),
.arg(mapFile, map->errorString()); qPrintable(map->errorString()));
return; delete map;
} }
} }
} }
if (_maps.isEmpty()) { if (_maps.isEmpty()) {
_errorString = "No maps found in atlas"; _errorString = "No usable map found in atlas";
return; return;
} }
_valid = true; _valid = true;
} }
RectC Atlas::llBounds(const Projection &proj) RectC Atlas::llBounds()
{ {
RectC bounds; RectC bounds;
for (int i = 0; i < _maps.size(); i++) for (int i = 0; i < _maps.size(); i++)
bounds |= _maps.at(i)->llBounds(proj); bounds |= _maps.at(i)->llBounds();
return bounds; return bounds;
} }
@ -295,18 +331,34 @@ void Atlas::unload()
_bounds.clear(); _bounds.clear();
} }
Map *Atlas::createTAR(const QString &path, bool *isDir) Map *Atlas::createTAR(const QString &path, const Projection &proj, bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = true; *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) if (isDir)
*isDir = true; *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 Q_OBJECT
public: 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;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &proj); RectC llBounds();
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -37,8 +38,10 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *createTAR(const QString &path, bool *isDir); static Map *createTAR(const QString &path, const Projection &proj,
static Map *createTBA(const QString &path, bool *isDir); bool *isDir);
static Map *createTBA(const QString &path, const Projection &proj,
bool *isDir);
private: private:
struct Zoom { struct Zoom {
@ -61,6 +64,9 @@ private:
void computeZooms(); void computeZooms();
void computeBounds(); void computeBounds();
friend QDebug operator<<(QDebug dbg, const Bounds &bounds);
friend QDebug operator<<(QDebug dbg, const Zoom &zoom);
QString _name; QString _name;
QList<OziMap*> _maps; QList<OziMap*> _maps;
@ -73,4 +79,9 @@ private:
QString _errorString; 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 #endif // ATLAS_H

View File

@ -462,8 +462,10 @@ void BSBMap::unload()
_img = 0; _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) if (isMap)
*isMap = false; *isMap = false;

View File

@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
bool parseBSB(const QByteArray &line); 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) if (isDir)
*isDir = true; *isDir = true;

View File

@ -22,7 +22,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;} RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -44,7 +44,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private slots:
void jobFinished(ENCJob *job); 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) if (isMap)
*isMap = false; *isMap = false;

View File

@ -23,7 +23,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;} RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -45,7 +45,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private slots:
void jobFinished(ENCJob *job); void jobFinished(ENCJob *job);

View File

@ -301,8 +301,10 @@ void GEMFMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp)
painter->drawPixmap(tp, pixmap); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -14,7 +14,7 @@ public:
GEMFMap(const QString &fileName, QObject *parent = 0); GEMFMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
int zoom() const {return _zi;} int zoom() const {return _zi;}
void setZoom(int zoom) {_zi = zoom;} void setZoom(int zoom) {_zi = zoom;}
@ -35,7 +35,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
struct Region { struct Region {

View File

@ -73,8 +73,10 @@ void GeoTIFFMap::unload()
_img = 0; _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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -29,7 +29,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
Projection _projection; 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) if (isDir)
*isDir = false; *isDir = false;
return new IMGMap(path, 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) if (isDir)
*isDir = true; *isDir = true;

View File

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

View File

@ -19,7 +19,7 @@ public:
~JNXMap(); ~JNXMap();
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom) {_zoom = zoom;} void setZoom(int zoom) {_zoom = zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
struct Tile { struct Tile {

View File

@ -484,8 +484,10 @@ void KMZMap::draw(QPainter *painter, const QRectF &rect, int mapIndex)
painter->restore(); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -18,7 +18,7 @@ public:
KMZMap(const QString &fileName, QObject *parent = 0); KMZMap(const QString &fileName, QObject *parent = 0);
~KMZMap(); ~KMZMap();
RectC llBounds(const Projection &) {return _llbounds;} RectC llBounds() {return _llbounds;}
QRectF bounds(); QRectF bounds();
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
class Overlay { class Overlay {

View File

@ -4,6 +4,7 @@
#define SAMPLES 100 #define SAMPLES 100
#define DELTA 1e-6
static void growLeft(const Coordinates &c, RectC &rect) static void growLeft(const Coordinates &c, RectC &rect)
{ {
@ -29,12 +30,8 @@ static void growBottom(const Coordinates &c, RectC &rect)
rect.setBottom(c.lat()); 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()); QRectF b(bounds());
double dx = b.width() / SAMPLES; double dx = b.width() / SAMPLES;
double dy = b.height() / SAMPLES; double dy = b.height() / SAMPLES;
@ -55,14 +52,27 @@ RectC Map::llBounds(const Projection &proj)
growRight(xy2ll(QPointF(b.right(), y)), rect); 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; return rect;
} }
qreal Map::resolution(const QRectF &rect) qreal Map::resolution(const QRectF &rect)
{ {
qreal cy = rect.center().y(); /* The haversine formula used in Coordinates::distanceTo() only gives
QPointF cl(rect.left(), cy); "half world" distances and shorter so we have to use only the center
QPointF cr(rect.right(), cy); "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 ds = xy2ll(cl).distanceTo(xy2ll(cr));
qreal ps = QLineF(cl, cr).length(); qreal ps = QLineF(cl, cr).length();

View File

@ -28,19 +28,19 @@ public:
: QObject(parent), _path(path) {} : QObject(parent), _path(path) {}
virtual ~Map() {} virtual ~Map() {}
/* Functions available since map creation */
const QString &path() const {return _path;} const QString &path() const {return _path;}
virtual QString name() const {return Util::file2name(path());} virtual QString name() const {return Util::file2name(path());}
virtual RectC llBounds(const Projection &proj);
virtual bool isValid() const {return true;} virtual bool isValid() const {return true;}
virtual bool isReady() const {return true;} virtual bool isReady() const {return true;}
virtual QString errorString() const {return QString();} virtual QString errorString() const {return QString();}
/* Functions that shall be called after load() */
virtual void load(const Projection &, const Projection &, qreal, bool) {} virtual void load(const Projection &, const Projection &, qreal, bool) {}
virtual void unload() {} 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 QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect); virtual qreal resolution(const QRectF &rect);

View File

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

View File

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

View File

@ -52,7 +52,7 @@ public:
MapsforgeMap(const QString &fileName, QObject *parent = 0); MapsforgeMap(const QString &fileName, QObject *parent = 0);
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _data.bounds();} RectC llBounds() {return _data.bounds();}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -74,7 +74,7 @@ public:
bool isValid() const {return _data.isValid();} bool isValid() const {return _data.isValid();}
QString errorString() const {return _data.errorString();} 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: private slots:
void jobFinished(MapsforgeMapJob *job); 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; Config config;
QFile file(path); QFile file(path);

View File

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

View File

@ -338,8 +338,10 @@ Coordinates MBTilesMap::xy2ll(const QPointF &p)
* coordinatesRatio()); * 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -13,7 +13,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zi;} int zoom() const {return _zi;}
@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
qreal tileSize() const; qreal tileSize() const;

View File

@ -590,8 +590,10 @@ Coordinates OruxMap::xy2ll(const QPointF &p)
return z.projection.xy2ll(z.transform.img2proj(p * _mapRatio)); 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) if (isDir)
*isDir = true; *isDir = true;

View File

@ -40,7 +40,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
struct Zoom { 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); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -11,7 +11,7 @@ public:
OsmdroidMap(const QString &fileName, QObject *parent = 0); OsmdroidMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
int limitZoom(int zoom) const; int limitZoom(int zoom) const;

View File

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

View File

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

View File

@ -28,7 +28,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
bool readName(QDataStream &stream); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
struct Header { 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); 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) if (isDir)
*isDir = false; *isDir = false;

View File

@ -11,7 +11,7 @@ public:
SqliteMap(const QString &fileName, QObject *parent = 0); SqliteMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} 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: private:
int limitZoom(int zoom) const; int limitZoom(int zoom) const;

View File

@ -6,6 +6,7 @@
#include <QtConcurrent> #include <QtConcurrent>
#include "tileloader.h" #include "tileloader.h"
#define SUBSTITUTE_CHAR '$'
class TileImage class TileImage
{ {
@ -34,6 +35,27 @@ private:
int _scaledSize; 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) static QString quadKey(const QPoint &xy, int zoom)
{ {
QString qk; QString qk;
@ -198,7 +220,10 @@ QUrl TileLoader::tileUrl(const FetchTile &tile) const
QString TileLoader::tileFile(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().x()) + QLatin1Char('-')
+ QString::number(tile.xy().y()); + QString::number(tile.xy().y());
} }

View File

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

View File

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