1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-03-13 18:47:45 +01:00

Merge branch 'master' into android-latest

This commit is contained in:
Martin Tůma 2025-03-08 15:32:39 +01:00
commit 977fea9330
53 changed files with 5629 additions and 5140 deletions

View File

@ -1,4 +1,4 @@
version: 13.36.{build} version: 13.37.{build}
configuration: configuration:
- Release - Release

View File

@ -5,7 +5,7 @@ GPS log file formats.
## Features ## Features
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON, * Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON,
OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN, ONmove OMD/GHP, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN, ONmove OMD/GHP,
TwoNav (TRK, RTE, WPT), GPSDump WPT and geotagged JPEG files. TwoNav (TRK, RTE, WPT), GPSDump WPT, 70mai GPS logs and geotagged JPEG files.
* Opens geo URIs (RFC 5870). * Opens geo URIs (RFC 5870).
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, * User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS,
QuadTiles). QuadTiles).

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 13.36 VERSION = 13.37
QT += core \ QT += core \
gui \ gui \
@ -117,6 +117,8 @@ HEADERS += src/common/config.h \
src/data/gpsdumpparser.h \ src/data/gpsdumpparser.h \
src/data/style.h \ src/data/style.h \
src/data/twonavparser.h \ src/data/twonavparser.h \
src/data/txtparser.h \
src/map/ENC/data.h \
src/map/IMG/light.h \ src/map/IMG/light.h \
src/map/downloader.h \ src/map/downloader.h \
src/map/demloader.h \ src/map/demloader.h \
@ -343,6 +345,7 @@ SOURCES += src/main.cpp \
src/GUI/pngexportdialog.cpp \ src/GUI/pngexportdialog.cpp \
src/GUI/projectioncombobox.cpp \ src/GUI/projectioncombobox.cpp \
src/GUI/passwordedit.cpp \ src/GUI/passwordedit.cpp \
src/data/txtparser.cpp \
src/map/downloader.cpp \ src/map/downloader.cpp \
src/map/demloader.cpp \ src/map/demloader.cpp \
src/map/ENC/atlasdata.cpp \ src/map/ENC/atlasdata.cpp \

View File

@ -216,6 +216,7 @@
<file alias="tanker-anchorage.png">icons/map/marine/tanker-anchorage.png</file> <file alias="tanker-anchorage.png">icons/map/marine/tanker-anchorage.png</file>
<file alias="nature-reserve-line.png">icons/map/marine/nature-reserve-line.png</file> <file alias="nature-reserve-line.png">icons/map/marine/nature-reserve-line.png</file>
<file alias="sanctuary-line.png">icons/map/marine/sanctuary-line.png</file> <file alias="sanctuary-line.png">icons/map/marine/sanctuary-line.png</file>
<file alias="fishing-farm.png">icons/map/marine/fishing-farm.png</file>
</qresource> </qresource>
<!-- Patterns (Mapsforge) --> <!-- Patterns (Mapsforge) -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,8 @@
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC, <li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC,
OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP, OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP,
Garmin GPI &amp; CSV, TomTom OV2 &amp; ITN, ONmove OMD/GHP, Garmin GPI &amp; CSV, TomTom OV2 &amp; ITN, ONmove OMD/GHP,
TwoNav (TRK, RTE, WPT), GPSDump WPT and geotagged JPEG TwoNav (TRK, RTE, WPT), GPSDump WPT, 70mai GPS logs and
files.</li> geotagged JPEG files.</li>
<li>Opens geo URIs (RFC 5870).</li> <li>Opens geo URIs (RFC 5870).</li>
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS, <li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
WMS, TMS, QuadTiles).</li> WMS, TMS, QuadTiles).</li>
@ -113,6 +113,7 @@
<mimetype>application/vnd.iho.s57-catalogue</mimetype> <mimetype>application/vnd.iho.s57-catalogue</mimetype>
<mimetype>application/vnd.gpsdump.wpt</mimetype> <mimetype>application/vnd.gpsdump.wpt</mimetype>
<mimetype>application/vnd.gpstuner.gmi</mimetype> <mimetype>application/vnd.gpstuner.gmi</mimetype>
<mimetype>application/vnd.70mai.txt</mimetype>
<mimetype>x-scheme-handler/geo</mimetype> <mimetype>x-scheme-handler/geo</mimetype>
</mimetypes> </mimetypes>
</component> </component>

View File

@ -16,4 +16,4 @@ Icon=gpxsee
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt
MimeType=x-scheme-handler/geo;application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt;application/vnd.gpstuner.gmi MimeType=x-scheme-handler/geo;application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt;application/vnd.gpstuner.gmi;application/vnd.70mai.txt

View File

@ -188,6 +188,16 @@
<glob pattern="*.wpt"/> <glob pattern="*.wpt"/>
</mime-type> </mime-type>
<mime-type type="application/vnd.70mai.txt">
<comment>70mai GPS Log File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text/plain"/>
<magic>
<match type="string" offset="0" value="$V02"/>
</magic>
<glob pattern="*.txt"/>
</mime-type>
<!-- Maps --> <!-- Maps -->
<mime-type type="application/vnd.garmin.img"> <mime-type type="application/vnd.garmin.img">

View File

@ -736,6 +736,20 @@
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Viewer</string> <string>Viewer</string>
</dict> </dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>txt</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.70mai.txt</string>
</array>
<key>CFBundleTypeName</key>
<string>70mai GPS Log File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array> </array>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@ -1718,6 +1732,27 @@
<string>application/vnd.iho.s57-catalogue</string> <string>application/vnd.iho.s57-catalogue</string>
</dict> </dict>
</dict> </dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.70mai.txt</string>
<key>UTTypeReferenceURL</key>
<string>https://forum.mapillary.com/t/using-the-70mai-a810-dashcam-for-mapillary/9130/7?u=boris</string>
<key>UTTypeDescription</key>
<string>70mai GPS Log File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>txt</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.70mai.txt</string>
</dict>
</dict>
</array> </array>
<key>UTExportedTypeDeclarations</key> <key>UTExportedTypeDeclarations</key>

View File

@ -49,7 +49,7 @@ Unicode true
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "13.36" !define VERSION "13.37"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"
@ -265,6 +265,7 @@ Section "GPXSee" SEC_APP
WriteRegStr HKCR ".gemf\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".gemf\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".000\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".000\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".031\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".031\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".txt\OpenWithList" "GPXSee.exe" ""
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
@ -492,6 +493,7 @@ Section "Uninstall"
DeleteRegValue HKCR ".gemf\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".gemf\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".000\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".000\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".031\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".031\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".txt\OpenWithList" "GPXSee.exe"
DeleteRegKey HKCR "Applications\GPXSee.exe" DeleteRegKey HKCR "Applications\GPXSee.exe"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'

View File

@ -1193,10 +1193,12 @@ void GUI::loadData(const Data &data)
_time += track.time(); _time += track.time();
_movingTime += track.movingTime(); _movingTime += track.movingTime();
const QDateTime date = track.date().toTimeZone(_options.timeZone.zone()); const QDateTime date = track.date().toTimeZone(_options.timeZone.zone());
if (_dateRange.first.isNull() || _dateRange.first > date) if (date.isValid()) {
_dateRange.first = date; if (_dateRange.first.isNull() || _dateRange.first > date)
if (_dateRange.second.isNull() || _dateRange.second < date) _dateRange.first = date;
_dateRange.second = date; if (_dateRange.second.isNull() || _dateRange.second < date)
_dateRange.second = date;
}
} }
_trackCount += data.tracks().count(); _trackCount += data.tracks().count();

View File

@ -7,15 +7,18 @@ RFC 4180 parser with the following enchancements:
- allows LF line ends in addition to CRLF line ends - allows LF line ends in addition to CRLF line ends
*/ */
bool CSV::readEntry(QByteArrayList &list) bool CSV::readEntry(QByteArrayList &list, int limit)
{ {
int state = 0; int state = 0, len = 0;
char c; char c;
QByteArray field; QByteArray field;
list.clear(); list.clear();
while (_device->getChar(&c)) { while (_device->getChar(&c)) {
if (limit && ++len > limit)
return false;
switch (state) { switch (state) {
case 0: case 0:
if (c == '\r') if (c == '\r')

View File

@ -9,7 +9,7 @@ public:
CSV(QIODevice *device, char delimiter = ',') CSV(QIODevice *device, char delimiter = ',')
: _device(device), _delimiter(delimiter), _line(1) {} : _device(device), _delimiter(delimiter), _line(1) {}
bool readEntry(QByteArrayList &list); bool readEntry(QByteArrayList &list, int limit = 4096);
bool atEnd() const {return _device->atEnd();} bool atEnd() const {return _device->atEnd();}
int line() const {return _line;} int line() const {return _line;}

View File

@ -53,7 +53,7 @@ public:
bool intersects(const RectC &r) const bool intersects(const RectC &r) const
{return (right() >= r.left() && bottom() <= r.top() && left() <= r.right() {return (right() >= r.left() && bottom() <= r.top() && left() <= r.right()
&& top() >= r.bottom());} && top() >= r.bottom());}
bool contains(const Coordinates&c) const bool contains(const Coordinates &c) const
{return (c.lon() >= left() && c.lon() <= right() && c.lat() <= top() {return (c.lon() >= left() && c.lon() <= right() && c.lat() <= top()
&& c.lat() >= bottom());} && c.lat() >= bottom());}

View File

@ -115,7 +115,7 @@ public:
/// Count the data elements in this container. This is slow as no internal /// Count the data elements in this container. This is slow as no internal
/// counter is maintained. /// counter is maintained.
int Count(); int Count() const;
/// Iterator is not remove safe. /// Iterator is not remove safe.
@ -363,7 +363,7 @@ protected:
void* a_context) const; void* a_context) const;
void RemoveAllRec(Node* a_node); void RemoveAllRec(Node* a_node);
void Reset(); void Reset();
void CountRec(Node* a_node, int& a_count); void CountRec(Node* a_node, int& a_count) const;
/// Root of tree /// Root of tree
Node* m_root; Node* m_root;
@ -473,7 +473,7 @@ int RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDI
RTREE_TEMPLATE RTREE_TEMPLATE
int RTREE_QUAL::Count() int RTREE_QUAL::Count() const
{ {
int count = 0; int count = 0;
CountRec(m_root, count); CountRec(m_root, count);
@ -483,7 +483,7 @@ int RTREE_QUAL::Count()
RTREE_TEMPLATE RTREE_TEMPLATE
void RTREE_QUAL::CountRec(Node* a_node, int& a_count) void RTREE_QUAL::CountRec(Node* a_node, int& a_count) const
{ {
if (a_node->IsInternalNode()) { // not a leaf node if (a_node->IsInternalNode()) { // not a leaf node
for (int index = 0; index < a_node->m_count; ++index) for (int index = 0; index < a_node->m_count; ++index)

View File

@ -23,6 +23,7 @@
#include "onmoveparsers.h" #include "onmoveparsers.h"
#include "twonavparser.h" #include "twonavparser.h"
#include "gpsdumpparser.h" #include "gpsdumpparser.h"
#include "txtparser.h"
#include "data.h" #include "data.h"
@ -49,6 +50,7 @@ static OMDParser omd;
static GHPParser ghp; static GHPParser ghp;
static TwoNavParser twonav; static TwoNavParser twonav;
static GPSDumpParser gpsdump; static GPSDumpParser gpsdump;
static TXTParser txt;
static QMultiMap<QString, Parser*> parsers() static QMultiMap<QString, Parser*> parsers()
{ {
@ -82,6 +84,7 @@ static QMultiMap<QString, Parser*> parsers()
map.insert("rte", &twonav); map.insert("rte", &twonav);
map.insert("wpt", &twonav); map.insert("wpt", &twonav);
map.insert("wpt", &gpsdump); map.insert("wpt", &gpsdump);
map.insert("txt", &txt);
return map; return map;
} }
@ -241,6 +244,7 @@ QString Data::formats()
+ qApp->translate("Data", "SLF files") + " (*.slf);;" + qApp->translate("Data", "SLF files") + " (*.slf);;"
+ qApp->translate("Data", "SML files") + " (*.sml);;" + qApp->translate("Data", "SML files") + " (*.sml);;"
+ qApp->translate("Data", "TCX files") + " (*.tcx);;" + qApp->translate("Data", "TCX files") + " (*.tcx);;"
+ qApp->translate("Data", "70mai GPS log files") + " (*.txt);;"
+ qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;" + qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;"
+ qApp->translate("Data", "GPSDump files") + " (*.wpt);;" + qApp->translate("Data", "GPSDump files") + " (*.wpt);;"
+ qApp->translate("Data", "All files") + " (*)"; + qApp->translate("Data", "All files") + " (*)";

View File

@ -541,7 +541,7 @@ void KMLParser::photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints,
Waypoint w; Waypoint w;
QMap<QString, PolygonStyle> unused; QMap<QString, PolygonStyle> unused;
QMap<QString, LineStyle> unused2; QMap<QString, LineStyle> unused2;
static QRegularExpression re("\\$\\[[^\\]]+\\]"); static const QRegularExpression re("\\$\\[[^\\]]+\\]");
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name")) if (_reader.name() == QLatin1String("name"))

80
src/data/txtparser.cpp Normal file
View File

@ -0,0 +1,80 @@
#include <QTimeZone>
#include "common/csv.h"
#include "txtparser.h"
static Coordinates coordinates(const QByteArrayList &entry)
{
bool lonOk, latOk;
double lon = entry.at(3).toDouble(&lonOk);
double lat = entry.at(2).toDouble(&latOk);
return (lonOk && latOk) ? Coordinates(lon, lat) : Coordinates();
}
bool TXTParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
Q_UNUSED(waypoints);
CSV csv(file);
QByteArrayList entry;
SegmentData *sg = 0;
_errorLine = 1;
_errorString.clear();
while (!csv.atEnd()) {
if (!csv.readEntry(entry)) {
_errorString = "CSV parse error";
_errorLine = csv.line() - 1;
return false;
}
if (entry.size() == 1) {
if (entry.at(0) == "$V02") {
tracks.append(TrackData(SegmentData()));
sg = &tracks.last().last();
} else {
_errorString = "Invalid track start marker";
_errorLine = csv.line() - 1;
return false;
}
} else {
if (!sg) {
_errorString = "Missing start marker";
_errorLine = csv.line() - 1;
return false;
}
if (entry.size() == 13 && entry.at(1) == "A") {
Coordinates c(coordinates(entry));
if (!c.isValid()) {
_errorString = "Invalid coordinates";
_errorLine = csv.line() - 1;
return false;
}
Trackpoint tp(c);
bool ok;
qulonglong ts = entry.at(0).toULongLong(&ok);
if (!ok) {
_errorString = "Invalid timestamp";
_errorLine = csv.line() - 1;
return false;
}
tp.setTimestamp(QDateTime::fromSecsSinceEpoch(ts,
QTimeZone::utc()));
uint speed = entry.at(5).toULong(&ok);
if (ok)
tp.setSpeed(speed * 0.01);
if (c != Coordinates(0, 0))
sg->append(tp);
}
}
}
return true;
}

18
src/data/txtparser.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef TXTPARSER_H
#define TXTPARSER_H
#include "parser.h"
class TXTParser : public Parser
{
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
private:
QString _errorString;
int _errorLine;
};
#endif // TXTPARSER_H

View File

@ -39,15 +39,12 @@ bool AtlasData::polyCb(MapEntry *map, void *context)
ctx->cacheLock.unlock(); ctx->cacheLock.unlock();
MapData *data = new MapData(map->path); MapData *data = new MapData(map->path);
data->polygons(ctx->rect, ctx->polygons); data->polys(ctx->rect, ctx->polygons, ctx->lines);
data->lines(ctx->rect, ctx->lines);
ctx->cacheLock.lock(); ctx->cacheLock.lock();
ctx->cache.insert(map->path, data); ctx->cache.insert(map->path, data);
} else { } else
cached->polygons(ctx->rect, ctx->polygons); cached->polys(ctx->rect, ctx->polygons, ctx->lines);
cached->lines(ctx->rect, ctx->lines);
}
ctx->cacheLock.unlock(); ctx->cacheLock.unlock();
map->lock.unlock(); map->lock.unlock();

View File

@ -10,18 +10,18 @@ namespace ENC {
typedef QCache<QString, MapData> MapCache; typedef QCache<QString, MapData> MapCache;
class AtlasData class AtlasData : public Data
{ {
public: public:
AtlasData(MapCache &cache, QMutex &cacheLock) AtlasData(MapCache &cache, QMutex &cacheLock)
: _cache(cache), _cacheLock(cacheLock) {} : _cache(cache), _cacheLock(cacheLock) {}
~AtlasData(); virtual ~AtlasData();
void addMap(const RectC &bounds, const QString &path); void addMap(const RectC &bounds, const QString &path);
void polys(const RectC &rect, QList<MapData::Poly> *polygons, virtual void polys(const RectC &rect, QList<MapData::Poly> *polygons,
QList<MapData::Line> *lines); QList<MapData::Line> *lines);
void points(const RectC &rect, QList<MapData::Point> *points); virtual void points(const RectC &rect, QList<MapData::Point> *points);
private: private:
struct MapEntry { struct MapEntry {

View File

@ -3,6 +3,7 @@
#define CATACH 8 #define CATACH 8
#define CATBUA 10 #define CATBUA 10
#define CATCOV 18
#define CATDIS 21 #define CATDIS 21
#define CATHAF 30 #define CATHAF 30
#define CATLMK 35 #define CATLMK 35

79
src/map/ENC/data.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef ENC_DATA_H
#define ENC_DATA_H
#include "common/rectc.h"
#include "common/polygon.h"
namespace ENC {
class Data
{
public:
typedef QMap<uint, QByteArray> Attributes;
class Poly {
public:
Poly(uint type, const Polygon &path, const Attributes &attr, uint HUNI);
RectC bounds() const {return _path.boundingRect();}
const Polygon &path() const {return _path;}
uint type() const {return _type;}
const Attributes &attributes() const {return _attr;}
uint HUNI() const {return _HUNI;}
private:
uint _type;
Polygon _path;
Attributes _attr;
uint _HUNI;
};
class Line {
public:
Line(uint type, const QVector<Coordinates> &path, const Attributes &attr);
RectC bounds() const;
const QVector<Coordinates> &path() const {return _path;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
private:
uint _type;
QVector<Coordinates> _path;
QString _label;
Attributes _attr;
};
class Point {
public:
Point(uint type, const Coordinates &c, const Attributes &attr,
uint HUNI, bool polygon = false);
Point(uint type, const Coordinates &s, const QString &label);
const Coordinates &pos() const {return _pos;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
bool polygon() const {return _polygon;}
bool operator<(const Point &other) const
{return _id < other._id;}
private:
uint _type;
Coordinates _pos;
QString _label;
quint64 _id;
Attributes _attr;
bool _polygon;
};
virtual void polys(const RectC &rect, QList<Data::Poly> *polygons,
QList<Data::Line> *lines) = 0;
virtual void points(const RectC &rect, QList<Data::Point> *points) = 0;
};
}
#endif // ENC_DATA_H

View File

@ -141,13 +141,12 @@ int ISO8211::readDR(QVector<FieldDefinition> &fields)
bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields) bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
{ {
static QRegularExpression re("(\\d*)(\\w+)\\(*(\\d*)\\)*"); static const QRegularExpression re("(\\d*)(\\w+)\\(*(\\d*)\\)*");
QByteArray ba; QByteArray ba(def.size, Qt::Initialization::Uninitialized);
bool repeat = false; bool repeat = false;
QVector<SubFieldDefinition> defs; QVector<SubFieldDefinition> defs;
QVector<QByteArray> defTags; QVector<QByteArray> defTags;
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()))
return false; return false;
@ -236,9 +235,8 @@ bool ISO8211::readDDR()
bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def, bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
const QVector<SubFieldDefinition> &fields, bool repeat, Data &data) const QVector<SubFieldDefinition> &fields, bool repeat, Data &data)
{ {
QByteArray ba; QByteArray ba(def.size, Qt::Initialization::Uninitialized);
ba.resize(def.size);
if (!(_file.seek(pos + def.pos) if (!(_file.seek(pos + def.pos)
&& _file.read(ba.data(), ba.size()) == ba.size())) && _file.read(ba.data(), ba.size()) == ba.size()))
return false; return false;
@ -248,8 +246,7 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
const char *ep = ba.constData() + ba.size() - 1; const char *ep = ba.constData() + ba.size() - 1;
do { do {
QVector<QVariant> row; QVector<QVariant> row(fields.size());
row.resize(fields.size());
for (int i = 0; i < fields.size(); i++) { for (int i = 0; i < fields.size(); i++) {
const SubFieldDefinition &f = fields.at(i); const SubFieldDefinition &f = fields.at(i);

View File

@ -362,6 +362,8 @@ MapData::Point::Point(uint type, const Coordinates &c, const Attributes &attr,
subtype = CATACH; subtype = CATACH;
else if (type == I_ACHARE) else if (type == I_ACHARE)
subtype = I_CATACH; subtype = I_CATACH;
else if (type == MARKUL)
subtype = CATMFA;
QList<QByteArray> list(_attr.value(subtype).split(',')); QList<QByteArray> list(_attr.value(subtype).split(','));
std::sort(list.begin(), list.end()); std::sort(list.begin(), list.end());
@ -423,6 +425,8 @@ MapData::Poly::Poly(uint type, const Polygon &path, const Attributes &attr,
subtype = CATMFA; subtype = CATMFA;
else if (type == I_BERTHS) else if (type == I_BERTHS)
subtype = I_CATBRT; subtype = I_CATBRT;
else if (type == M_COVR)
subtype = CATCOV;
switch (type) { switch (type) {
case DEPARE: case DEPARE:
@ -864,7 +868,7 @@ MapData::~MapData()
delete _points.GetAt(pit); delete _points.GetAt(pit);
} }
void MapData::points(const RectC &rect, QList<Point> *points) const void MapData::points(const RectC &rect, QList<Point> *points)
{ {
double min[2], max[2]; double min[2], max[2];
@ -874,18 +878,12 @@ void MapData::points(const RectC &rect, QList<Point> *points) const
_lines.Search(min, max, linePointCb, points); _lines.Search(min, max, linePointCb, points);
} }
void MapData::lines(const RectC &rect, QList<Line> *lines) const void MapData::polys(const RectC &rect, QList<Poly> *polygons,
QList<Line> *lines)
{ {
double min[2], max[2]; double min[2], max[2];
rectcBounds(rect, min, max); rectcBounds(rect, min, max);
_lines.Search(min, max, lineCb, lines); _lines.Search(min, max, lineCb, lines);
}
void MapData::polygons(const RectC &rect, QList<Poly> *polygons) const
{
double min[2], max[2];
rectcBounds(rect, min, max);
_areas.Search(min, max, polygonCb, polygons); _areas.Search(min, max, polygonCb, polygons);
} }

View File

@ -1,82 +1,21 @@
#ifndef ENC_MAPDATA_H #ifndef ENC_MAPDATA_H
#define ENC_MAPDATA_H #define ENC_MAPDATA_H
#include "common/rectc.h"
#include "common/rtree.h" #include "common/rtree.h"
#include "common/polygon.h"
#include "iso8211.h" #include "iso8211.h"
#include "data.h"
namespace ENC { namespace ENC {
class MapData class MapData : public Data
{ {
public: public:
typedef QMap<uint, QByteArray> Attributes;
class Poly {
public:
Poly(uint type, const Polygon &path, const Attributes &attr, uint HUNI);
RectC bounds() const {return _path.boundingRect();}
const Polygon &path() const {return _path;}
uint type() const {return _type;}
const Attributes &attributes() const {return _attr;}
uint HUNI() const {return _HUNI;}
private:
uint _type;
Polygon _path;
Attributes _attr;
uint _HUNI;
};
class Line {
public:
Line(uint type, const QVector<Coordinates> &path, const Attributes &attr);
RectC bounds() const;
const QVector<Coordinates> &path() const {return _path;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
private:
uint _type;
QVector<Coordinates> _path;
QString _label;
Attributes _attr;
};
class Point {
public:
Point(uint type, const Coordinates &c, const Attributes &attr,
uint HUNI, bool polygon = false);
Point(uint type, const Coordinates &s, const QString &label);
const Coordinates &pos() const {return _pos;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
bool polygon() const {return _polygon;}
bool operator<(const Point &other) const
{return _id < other._id;}
private:
uint _type;
Coordinates _pos;
QString _label;
quint64 _id;
Attributes _attr;
bool _polygon;
};
MapData(const QString &path); MapData(const QString &path);
~MapData(); virtual ~MapData();
void polygons(const RectC &rect, QList<Poly> *polygons) const; virtual void polys(const RectC &rect, QList<Poly> *polygons,
void lines(const RectC &rect, QList<Line> *lines) const; QList<Line> *lines);
void points(const RectC &rect, QList<Point> *points) const; virtual void points(const RectC &rect, QList<Point> *points);
private: private:
struct Sounding { struct Sounding {

View File

@ -28,14 +28,14 @@ static double angle(uint type, const QVariant &param)
? 90 + param.toDouble() : NAN; ? 90 + param.toDouble() : NAN;
} }
static bool showLabel(const QImage *img, const Range &range, int zoom, int type) bool RasterTile::showLabel(const QImage *img, int type) const
{ {
if (type>>16 == I_DISMAR) if (type>>16 == I_DISMAR)
return true; return true;
int limit = (!range.size()) int limit = (!_zoomRange.size())
? range.min() : range.min() + (range.size() + 1) / 2; ? _zoomRange.min() : _zoomRange.min() + (_zoomRange.size() + 1) / 2;
if ((img || (type>>16 == SOUNDG)) && (zoom < limit)) if ((img || (type>>16 == SOUNDG)) && (_zoom < limit))
return false; return false;
return true; return true;
@ -139,10 +139,10 @@ static void drawArrow(QPainter *painter, const QPolygonF &polygon, uint type)
} }
void RasterTile::drawArrows(QPainter *painter, void RasterTile::drawArrows(QPainter *painter,
const QList<MapData::Point> &points) const const QList<Data::Point> &points) const
{ {
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
if (point.type()>>16 == TSSLPT || point.type()>>16 == RCTLPT) { if (point.type()>>16 == TSSLPT || point.type()>>16 == RCTLPT) {
QPolygonF polygon(tsslptArrow(ll2xy(point.pos()), QPolygonF polygon(tsslptArrow(ll2xy(point.pos()),
@ -153,11 +153,11 @@ void RasterTile::drawArrows(QPainter *painter,
} }
void RasterTile::drawPolygons(QPainter *painter, void RasterTile::drawPolygons(QPainter *painter,
const QList<MapData::Poly> &polygons) const const QList<Data::Poly> &polygons) const
{ {
for (int n = 0; n < _style->drawOrder().size(); n++) { for (int n = 0; n < _style->drawOrder().size(); n++) {
for (int i = 0; i < polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly &poly = polygons.at(i); const Data::Poly &poly = polygons.at(i);
if (poly.type() != _style->drawOrder().at(n)) if (poly.type() != _style->drawOrder().at(n))
continue; continue;
const Style::Polygon &style = _style->polygon(poly.type()); const Style::Polygon &style = _style->polygon(poly.type());
@ -169,8 +169,13 @@ void RasterTile::drawPolygons(QPainter *painter,
} else { } else {
if (style.brush() != Qt::NoBrush) { if (style.brush() != Qt::NoBrush) {
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
QPainterPath path(painterPath(poly.path()));
if (poly.type() == TYPE(DRGARE)) {
painter->setBrush(Qt::white);
painter->drawPath(path);
}
painter->setBrush(style.brush()); painter->setBrush(style.brush());
painter->drawPath(painterPath(poly.path())); painter->drawPath(path);
} }
if (style.pen() != Qt::NoPen) { if (style.pen() != Qt::NoPen) {
painter->setPen(style.pen()); painter->setPen(style.pen());
@ -185,12 +190,12 @@ void RasterTile::drawPolygons(QPainter *painter,
} }
} }
void RasterTile::drawLines(QPainter *painter, const QList<MapData::Line> &lines) const void RasterTile::drawLines(QPainter *painter, const QList<Data::Line> &lines) const
{ {
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Line &line = lines.at(i); const Data::Line &line = lines.at(i);
const Style::Line &style = _style->line(line.type()); const Style::Line &style = _style->line(line.type());
if (!style.img().isNull()) { if (!style.img().isNull()) {
@ -221,11 +226,11 @@ static QRectF lightRect(const QPointF &pos, double range)
} }
void RasterTile::drawSectorLights(QPainter *painter, void RasterTile::drawSectorLights(QPainter *painter,
const QList<SectorLight> &lights) const const QMultiMap<Coordinates, SectorLight> &lights) const
{ {
for (int i = 0; i < lights.size(); i++) { for (auto it = lights.cbegin(); it != lights.cend(); ++it) {
const SectorLight &l = lights.at(i); const SectorLight &l = it.value();
QPointF pos(ll2xy(l.pos)); QPointF pos(ll2xy(it.key()));
QRectF rect(lightRect(pos, (l.range == 0) ? 6 : l.range)); QRectF rect(lightRect(pos, (l.range == 0) ? 6 : l.range));
double a1 = -(l.end + 90); double a1 = -(l.end + 90);
double a2 = -(l.start + 90); double a2 = -(l.start + 90);
@ -257,49 +262,45 @@ void RasterTile::drawSectorLights(QPainter *painter,
} }
} }
void RasterTile::processPoints(QList<MapData::Point> &points, void RasterTile::processPoints(const QList<Data::Point> &points,
QList<TextItem*> &textItems, QList<TextItem*> &lights, QList<TextItem*> &textItems, QList<TextItem*> &lightItems,
QList<SectorLight> &sectorLights) QMultiMap<Coordinates, SectorLight> &sectorLights, bool overZoom) const
{ {
LightMap lightsMap; QMap<Coordinates, Style::Color> lights;
SignalSet signalsSet; QSet<Coordinates> sigs;
QSet<Coordinates> slMap;
int i; int i;
std::sort(points.begin(), points.end());
/* Lights & Signals */ /* Lights & Signals */
for (i = 0; i < points.size(); i++) { for (i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
if (point.type()>>16 == LIGHTS) { if (point.type()>>16 == LIGHTS) {
const MapData::Attributes &attr = point.attributes(); const Data::Attributes &attr = point.attributes();
Style::Color color = (Style::Color)(attr.value(COLOUR).toUInt()); Style::Color color = (Style::Color)(attr.value(COLOUR).toUInt());
double range = attr.value(VALNMR).toDouble(); double range = attr.value(VALNMR).toDouble();
if (attr.contains(SECTR1) if (attr.contains(SECTR1)
|| (range >= MAJOR_RANGE && !(point.type() & 0xFFFF))) { || (range >= MAJOR_RANGE && !(point.type() & 0xFFFF))) {
sectorLights.append(SectorLight(point.pos(), color, sectorLights.insert(point.pos(), SectorLight(color,
attr.value(LITVIS).toUInt(), range, attr.value(LITVIS).toUInt(), range,
attr.value(SECTR1).toDouble(), attr.value(SECTR2).toDouble())); attr.value(SECTR1).toDouble(), attr.value(SECTR2).toDouble()));
slMap.insert(point.pos());
} else } else
lightsMap.insert(point.pos(), color); lights.insert(point.pos(), color);
} else if (point.type()>>16 == FOGSIG) } else if (point.type()>>16 == FOGSIG)
signalsSet.insert(point.pos()); sigs.insert(point.pos());
else else
break; break;
} }
/* Everything else */ /* Everything else */
for ( ; i < points.size(); i++) { for ( ; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
QPoint pos(ll2xy(point.pos()).toPoint()); QPoint pos(ll2xy(point.pos()).toPoint());
const Style::Point &style = _style->point(point.type()); const Style::Point &style = _style->point(point.type());
const QString *label = point.label().isEmpty() ? 0 : &(point.label()); const QString *label = point.label().isEmpty() ? 0 : &(point.label());
const QImage *img = style.img().isNull() ? 0 : &style.img(); const QImage *img = style.img().isNull() ? 0 : &style.img();
const QFont *fnt = showLabel(img, _zoomRange, _zoom, point.type()) const QFont *fnt = (overZoom || showLabel(img, point.type()))
? _style->font(style.textFontSize()) : 0; ? _style->font(style.textFontSize()) : 0;
const QColor *color = &style.textColor(); const QColor *color = &style.textColor();
const QColor *hColor = style.haloColor().isValid() const QColor *hColor = style.haloColor().isValid()
@ -313,25 +314,25 @@ void RasterTile::processPoints(QList<MapData::Point> &points,
TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img, TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img,
color, hColor, 0, 2, rotate); color, hColor, 0, 2, rotate);
if (item->isValid() && (slMap.contains(point.pos()) if (item->isValid() && (sectorLights.contains(point.pos())
|| (point.polygon() && img) || !item->collides(textItems))) { || (point.polygon() && img) || !item->collides(textItems))) {
textItems.append(item); textItems.append(item);
if (lightsMap.contains(point.pos())) if (lights.contains(point.pos()))
lights.append(new TextPointItem(pos + _style->lightOffset(), lightItems.append(new TextPointItem(pos + _style->lightOffset(),
0, 0, _style->light(lightsMap.value(point.pos())), 0, 0, 0, 0)); 0, 0, _style->light(lights.value(point.pos())), 0, 0, 0, 0));
if (signalsSet.contains(point.pos())) if (sigs.contains(point.pos()))
lights.append(new TextPointItem(pos + _style->signalOffset(), lightItems.append(new TextPointItem(pos + _style->signalOffset(),
0, 0, _style->signal(), 0, 0, 0, 0)); 0, 0, _style->signal(), 0, 0, 0, 0));
} else } else
delete item; delete item;
} }
} }
void RasterTile::processLines(const QList<MapData::Line> &lines, void RasterTile::processLines(const QList<Data::Line> &lines,
QList<TextItem*> &textItems) QList<TextItem*> &textItems) const
{ {
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Line &line = lines.at(i); const Data::Line &line = lines.at(i);
const Style::Line &style = _style->line(line.type()); const Style::Line &style = _style->line(line.type());
if (style.img().isNull() && style.pen() == Qt::NoPen) if (style.img().isNull() && style.pen() == Qt::NoPen)
@ -351,11 +352,46 @@ void RasterTile::processLines(const QList<MapData::Line> &lines,
} }
} }
void RasterTile::fetchData(QList<MapData::Poly> &polygons, void RasterTile::drawLevels(QPainter *painter, const QList<Level> &levels)
QList<MapData::Line> &lines, QList<MapData::Point> &points)
{ {
QPoint ttl(_rect.topLeft()); for (int i = levels.size() - 1; i >= 0; i--) {
QList<TextItem*> textItems, lightItems;
QMultiMap<Coordinates, SectorLight> sectorLights;
const Level &l = levels.at(i);
processPoints(l.points, textItems, lightItems, sectorLights, l.overZoom);
processLines(l.lines, textItems);
drawPolygons(painter, l.polygons);
drawLines(painter, l.lines);
drawArrows(painter, l.points);
drawTextItems(painter, lightItems);
drawSectorLights(painter, sectorLights);
drawTextItems(painter, textItems);
qDeleteAll(textItems);
qDeleteAll(lightItems);
}
}
QPainterPath RasterTile::shape(const QList<Data::Poly> &polygons) const
{
QPainterPath shp;
for (int i = 0; i < polygons.size(); i++) {
const Data::Poly &p = polygons.at(i);
if (p.type() == SUBTYPE(M_COVR, 1))
shp.addPath(painterPath(p.path()));
}
return shp;
}
QList<RasterTile::Level> RasterTile::fetchLevels()
{
QList<RasterTile::Level> list;
QPoint ttl(_rect.topLeft());
QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y() QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y()
+ _rect.height())); + _rect.height()));
RectD polyRectD(_transform.img2proj(polyRect.topLeft()), RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
@ -368,50 +404,41 @@ void RasterTile::fetchData(QList<MapData::Poly> &polygons,
_transform.img2proj(pointRect.bottomRight())); _transform.img2proj(pointRect.bottomRight()));
RectC pointRectC(pointRectD.toRectC(_proj, 20)); RectC pointRectC(pointRectD.toRectC(_proj, 20));
if (_map) { for (int i = 0; i < _data.size(); i++) {
_map->lines(polyRectC, &lines); Level level;
_map->polygons(polyRectC, &polygons);
_map->points(pointRectC, &points); _data.at(i)->polys(polyRectC, &level.polygons, &level.lines);
} else { _data.at(i)->points(pointRectC, &level.points);
_atlas->polys(polyRectC, &polygons, &lines); level.overZoom = i > 0;
_atlas->points(pointRectC, &points);
std::sort(level.points.begin(), level.points.end());
if (!level.isNull())
list.append(level);
if (_data.size() > 1 && shape(level.polygons).contains(_rect))
break;
} }
return list;
} }
void RasterTile::render() void RasterTile::render()
{ {
QList<Level> levels(fetchLevels());
QImage img(_rect.width() * _ratio, _rect.height() * _ratio, QImage img(_rect.width() * _ratio, _rect.height() * _ratio,
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
QList<MapData::Line> lines;
QList<MapData::Poly> polygons;
QList<MapData::Point> points;
QList<TextItem*> textItems, lights;
QList<SectorLight> sectorLights;
img.setDevicePixelRatio(_ratio); img.setDevicePixelRatio(_ratio);
img.fill(Qt::transparent); img.fill(Qt::transparent);
fetchData(polygons, lines, points);
processPoints(points, textItems, lights, sectorLights);
processLines(lines, textItems);
QPainter painter(&img); QPainter painter(&img);
painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y()); painter.translate(-_rect.x(), -_rect.y());
drawPolygons(&painter, polygons); drawLevels(&painter, levels);
drawLines(&painter, lines);
drawArrows(&painter, points);
drawTextItems(&painter, lights);
drawSectorLights(&painter, sectorLights);
drawTextItems(&painter, textItems);
qDeleteAll(textItems);
qDeleteAll(lights);
//painter.setPen(Qt::red); //painter.setPen(Qt::red);
//painter.setBrush(Qt::NoBrush); //painter.setBrush(Qt::NoBrush);

View File

@ -5,7 +5,7 @@
#include "common/range.h" #include "common/range.h"
#include "map/projection.h" #include "map/projection.h"
#include "map/transform.h" #include "map/transform.h"
#include "mapdata.h" #include "data.h"
#include "style.h" #include "style.h"
#include "atlasdata.h" #include "atlasdata.h"
@ -17,14 +17,17 @@ class RasterTile
{ {
public: public:
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Style *style, const MapData *data, int zoom, const Range &zoomRange, const Style *style, Data *data, int zoom,
const QRect &rect, qreal ratio) : const Range &zoomRange, const QRect &rect, qreal ratio) :
_proj(proj), _transform(transform), _style(style), _map(data), _atlas(0), _proj(proj), _transform(transform), _style(style),
_zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {} _zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio)
{
_data.append(data);
}
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Style *style, AtlasData *data, int zoom, const Range &zoomRange, const Style *style, const QList<Data*> &data, int zoom,
const QRect &rect, qreal ratio) : const Range &zoomRange, const QRect &rect, qreal ratio) :
_proj(proj), _transform(transform), _style(style), _map(0), _atlas(data), _proj(proj), _transform(transform), _style(style), _data(data),
_zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {} _zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -36,11 +39,10 @@ public:
private: private:
struct SectorLight struct SectorLight
{ {
SectorLight(const Coordinates &pos, Style::Color color, uint visibility, SectorLight(Style::Color color, uint visibility, double range,
double range, double start, double end) : pos(pos), color(color), double start, double end) : color(color), visibility(visibility),
visibility(visibility), range(range), start(start), end(end) {} range(range), start(start), end(end) {}
Coordinates pos;
Style::Color color; Style::Color color;
uint visibility; uint visibility;
double range; double range;
@ -48,11 +50,16 @@ private:
double end; double end;
}; };
typedef QMap<Coordinates, Style::Color> LightMap; struct Level {
typedef QSet<Coordinates> SignalSet; QList<Data::Line> lines;
QList<Data::Poly> polygons;
QList<Data::Point> points;
bool overZoom;
bool isNull() const
{return lines.isEmpty() && polygons.isEmpty() && points.isEmpty();}
};
void fetchData(QList<MapData::Poly> &polygons, QList<MapData::Line> &lines,
QList<MapData::Point> &points);
QPointF ll2xy(const Coordinates &c) const QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));} {return _transform.proj2img(_proj.ll2xy(c));}
QPainterPath painterPath(const Polygon &polygon) const; QPainterPath painterPath(const Polygon &polygon) const;
@ -60,25 +67,26 @@ private:
QVector<QPolygonF> polylineM(const QVector<Coordinates> &path) const; QVector<QPolygonF> polylineM(const QVector<Coordinates> &path) const;
QPolygonF tsslptArrow(const QPointF &p, qreal angle) const; QPolygonF tsslptArrow(const QPointF &p, qreal angle) const;
QPointF centroid(const QVector<Coordinates> &polygon) const; QPointF centroid(const QVector<Coordinates> &polygon) const;
void processPoints(QList<MapData::Point> &points, void processPoints(const QList<Data::Point> &points,
QList<TextItem*> &textItems, QList<TextItem *> &lights, QList<TextItem*> &textItems, QList<TextItem*> &lightItems,
QList<SectorLight> &sectorLights); QMultiMap<Coordinates, SectorLight> &sectorLights, bool overZoom) const;
void processLines(const QList<MapData::Line> &lines, void processLines(const QList<Data::Line> &lines,
QList<TextItem*> &textItems); QList<TextItem*> &textItems) const;
void drawArrows(QPainter *painter, const QList<MapData::Point> &points) const; void drawArrows(QPainter *painter, const QList<Data::Point> &points) const;
void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons) const; void drawPolygons(QPainter *painter, const QList<Data::Poly> &polygons) const;
void drawLines(QPainter *painter, const QList<MapData::Line> &lines) const; void drawLines(QPainter *painter, const QList<Data::Line> &lines) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems) const; void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems) const;
void drawSectorLights(QPainter *painter, const QList<SectorLight> &lights) const; void drawSectorLights(QPainter *painter,
const QMultiMap<Coordinates, SectorLight> &lights) const;
static bool polyCb(MapData *data, void *context); bool showLabel(const QImage *img, int type) const;
static bool pointCb(MapData *data, void *context); void drawLevels(QPainter *painter, const QList<Level> &levels);
QList<Level> fetchLevels();
QPainterPath shape(const QList<Data::Poly> &polygons) const;
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
const Style *_style; const Style *_style;
const MapData *_map; QList<Data *> _data;
AtlasData *_atlas;
int _zoom; int _zoom;
Range _zoomRange; Range _zoomRange;
QRect _rect; QRect _rect;

View File

@ -27,7 +27,6 @@ static QFont pixelSizeFont(int pixelSize)
void Style::polygonStyle() void Style::polygonStyle()
{ {
_polygons[TYPE(M_COVR)] = Polygon(QBrush(QColor(0xff, 0xff, 0xff)));
_polygons[TYPE(LNDARE)] = Polygon(QBrush(QColor(0xe8, 0xe0, 0x64))); _polygons[TYPE(LNDARE)] = Polygon(QBrush(QColor(0xe8, 0xe0, 0x64)));
_polygons[TYPE(BUAARE)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21))); _polygons[TYPE(BUAARE)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)));
_polygons[TYPE(BUISGL)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)), _polygons[TYPE(BUISGL)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)),
@ -141,6 +140,7 @@ void Style::polygonStyle()
1.5, Qt::DashLine)); 1.5, Qt::DashLine));
_polygons[TYPE(CBLARE)] = Polygon(QImage(":/marine/cable-area-line.png")); _polygons[TYPE(CBLARE)] = Polygon(QImage(":/marine/cable-area-line.png"));
_polygons[TYPE(PIPARE)] = Polygon(QImage(":/marine/pipeline-area-line.png")); _polygons[TYPE(PIPARE)] = Polygon(QImage(":/marine/pipeline-area-line.png"));
_polygons[SUBTYPE(MARKUL, 0)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[SUBTYPE(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png")); _polygons[SUBTYPE(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[TYPE(BERTHS)] = Polygon(Qt::NoBrush, QPen(QColor(0xeb, 0x49, 0xeb), _polygons[TYPE(BERTHS)] = Polygon(Qt::NoBrush, QPen(QColor(0xeb, 0x49, 0xeb),
1, Qt::DashLine)); 1, Qt::DashLine));
@ -152,19 +152,19 @@ void Style::polygonStyle()
1, Qt::DashDotLine)); 1, Qt::DashDotLine));
_drawOrder _drawOrder
<< TYPE(M_COVR) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0) << SUBTYPE(DEPARE, 1)
<< SUBTYPE(DEPARE, 1) << SUBTYPE(DEPARE, 2) << SUBTYPE(DEPARE, 3) << SUBTYPE(DEPARE, 2) << SUBTYPE(DEPARE, 3) << TYPE(UNSARE)
<< TYPE(UNSARE) << SUBTYPE(DEPARE, 4) << SUBTYPE(DEPARE, 5) << SUBTYPE(DEPARE, 4) << SUBTYPE(DEPARE, 5) << SUBTYPE(DEPARE, 6)
<< SUBTYPE(DEPARE, 6) << TYPE(LAKARE) << TYPE(CANALS) << TYPE(DYKCON) << TYPE(LAKARE) << TYPE(CANALS) << TYPE(DYKCON) << TYPE(RIVERS)
<< TYPE(RIVERS) << TYPE(DRGARE) << TYPE(FAIRWY) << TYPE(LOKBSN) << TYPE(DRGARE) << TYPE(FAIRWY) << TYPE(LOKBSN) << TYPE(I_LOKBSN)
<< TYPE(I_LOKBSN) << TYPE(BUAARE) << TYPE(BUISGL) << TYPE(SILTNK) << TYPE(BUAARE) << TYPE(BUISGL) << TYPE(SILTNK) << TYPE(AIRARE)
<< TYPE(AIRARE) << TYPE(BRIDGE) << TYPE(I_BRIDGE) << TYPE(TUNNEL) << TYPE(BRIDGE) << TYPE(I_BRIDGE) << TYPE(TUNNEL) << TYPE(I_TERMNL)
<< TYPE(I_TERMNL) << TYPE(SLCONS) << TYPE(I_SLCONS) << TYPE(PONTON) << TYPE(SLCONS) << TYPE(I_SLCONS) << TYPE(PONTON) << TYPE(I_PONTON)
<< TYPE(I_PONTON) << TYPE(HULKES) << TYPE(I_HULKES) << TYPE(FLODOC) << TYPE(HULKES) << TYPE(I_HULKES) << TYPE(FLODOC) << TYPE(I_FLODOC)
<< TYPE(I_FLODOC) << TYPE(DRYDOC) << TYPE(DAMCON) << TYPE(PYLONS) << TYPE(DRYDOC) << TYPE(DAMCON) << TYPE(PYLONS) << TYPE(MORFAC)
<< TYPE(MORFAC) << TYPE(GATCON) << TYPE(I_GATCON) << TYPE(BERTHS) << TYPE(GATCON) << TYPE(I_GATCON) << TYPE(BERTHS) << TYPE(I_BERTHS)
<< TYPE(I_BERTHS) << SUBTYPE(I_BERTHS, 6) << TYPE(DMPGRD) << TYPE(TSEZNE) << SUBTYPE(I_BERTHS, 6) << TYPE(DMPGRD) << TYPE(TSEZNE) << TYPE(OBSTRN)
<< TYPE(OBSTRN) << TYPE(UWTROC) << TYPE(DWRTPT) << SUBTYPE(ACHARE, 1) << TYPE(UWTROC) << TYPE(DWRTPT) << SUBTYPE(ACHARE, 1)
<< SUBTYPE(ACHARE, 2) << SUBTYPE(ACHARE, 3) << SUBTYPE(ACHARE, 4) << SUBTYPE(ACHARE, 2) << SUBTYPE(ACHARE, 3) << SUBTYPE(ACHARE, 4)
<< SUBTYPE(ACHARE, 5) << SUBTYPE(ACHARE, 6) << SUBTYPE(ACHARE, 7) << SUBTYPE(ACHARE, 5) << SUBTYPE(ACHARE, 6) << SUBTYPE(ACHARE, 7)
<< SUBTYPE(ACHARE, 8) << SUBTYPE(ACHARE, 9) << SUBTYPE(I_ACHARE, 1) << SUBTYPE(ACHARE, 8) << SUBTYPE(ACHARE, 9) << SUBTYPE(I_ACHARE, 1)
@ -180,7 +180,8 @@ void Style::polygonStyle()
<< SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 22) << SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 22)
<< SUBTYPE(I_RESARE, 22) << SUBTYPE(RESARE, 23) << SUBTYPE(I_RESARE, 23) << SUBTYPE(I_RESARE, 22) << SUBTYPE(RESARE, 23) << SUBTYPE(I_RESARE, 23)
<< SUBTYPE(RESARE, 1) << TYPE(CBLARE) << TYPE(PIPARE) << TYPE(PRCARE) << SUBTYPE(RESARE, 1) << TYPE(CBLARE) << TYPE(PIPARE) << TYPE(PRCARE)
<< TYPE(I_TRNBSN) << SUBTYPE(MARKUL, 3) << TYPE(CONZNE); << TYPE(I_TRNBSN) << SUBTYPE(MARKUL, 0) << SUBTYPE(MARKUL, 3)
<< TYPE(CONZNE);
} }
void Style::lineStyle(qreal ratio) void Style::lineStyle(qreal ratio)
@ -393,6 +394,8 @@ void Style::pointStyle(qreal ratio)
_points[TYPE(LNDARE)].setHaloColor(QColor()); _points[TYPE(LNDARE)].setHaloColor(QColor());
_points[TYPE(LNDRGN)].setHaloColor(QColor()); _points[TYPE(LNDRGN)].setHaloColor(QColor());
_points[TYPE(RADRFL)] = Point(QImage(":/marine/radar-reflector.png")); _points[TYPE(RADRFL)] = Point(QImage(":/marine/radar-reflector.png"));
_points[SUBTYPE(MARKUL, 0)] = Point(QImage(":/marine/fishing-farm.png"));
_points[SUBTYPE(MARKUL, 3)] = Point(QImage(":/marine/fishing-farm.png"));
_points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"), _points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"),
Small); Small);
@ -482,6 +485,7 @@ Style::Style(qreal ratio)
_lightRed = QImage(":/marine/light-red.png"); _lightRed = QImage(":/marine/light-red.png");
_lightGreen = QImage(":/marine/light-green.png"); _lightGreen = QImage(":/marine/light-green.png");
_lightYellow = QImage(":/marine/light-yellow.png"); _lightYellow = QImage(":/marine/light-yellow.png");
_lightWhite = QImage(":/marine/light-white.png");
_lightOffset = QPoint(11, 11); _lightOffset = QPoint(11, 11);
_signal = QImage(":/marine/fog-signal.png"); _signal = QImage(":/marine/fog-signal.png");
_signalOffset = QPoint(-9, 9); _signalOffset = QPoint(-9, 9);
@ -541,6 +545,7 @@ const QImage *Style::light(Color color) const
case Green: case Green:
return &_lightGreen; return &_lightGreen;
case White: case White:
return &_lightWhite;
case Yellow: case Yellow:
case Amber: case Amber:
case Orange: case Orange:
@ -558,6 +563,7 @@ QColor Style::color(Style::Color c)
case Green: case Green:
return Qt::green; return Qt::green;
case White: case White:
return Qt::white;
case Yellow: case Yellow:
case Amber: case Amber:
case Orange: case Orange:

View File

@ -121,7 +121,7 @@ private:
/* Fonts and images must be initialized after QGuiApplication! */ /* Fonts and images must be initialized after QGuiApplication! */
QFont _small, _normal, _large; QFont _small, _normal, _large;
QImage _light, _lightRed, _lightGreen, _lightYellow, _signal; QImage _light, _lightRed, _lightGreen, _lightYellow, _lightWhite, _signal;
QPoint _lightOffset, _signalOffset; QPoint _lightOffset, _signalOffset;
}; };

View File

@ -151,8 +151,7 @@ bool Downloader::doDownload(const Download &dl, const QList<HTTPHeader> &headers
for (int i = 0; i < headers.size(); i++) { for (int i = 0; i < headers.size(); i++) {
const HTTPHeader &hdr = headers.at(i); const HTTPHeader &hdr = headers.at(i);
request.setRawHeader(hdr.key(), hdr.value()); request.setRawHeader(hdr.key(), hdr.value());
// QByteArray::compare() not available in Qt < 5.12 if (!hdr.key().compare("User-Agent", Qt::CaseInsensitive))
if (!QString(hdr.key()).compare("User-Agent", Qt::CaseInsensitive))
userAgent = true; userAgent = true;
} }
if (!userAgent) if (!userAgent)

View File

@ -154,7 +154,7 @@ ENCAtlas::ENCAtlas(const QString &fileName, QObject *parent)
_zoom = zooms(_usage).min(); _zoom = zooms(_usage).min();
updateTransform(); updateTransform();
_cache.setMaxCost(10); _cache.setMaxCost(16);
_valid = true; _valid = true;
} }
@ -345,9 +345,21 @@ QString ENCAtlas::key(int zoom, const QPoint &xy) const
+ QString::number(xy.x()) + "_" + QString::number(xy.y()); + QString::number(xy.x()) + "_" + QString::number(xy.y());
} }
QList<Data*> ENCAtlas::levels() const
{
QList<Data*> list;
QMap<IntendedUsage, ENC::AtlasData*>::const_iterator it = _data.find(_usage);
do {
list.append(it.value());
} while (it-- != _data.cbegin());
return list;
}
void ENCAtlas::draw(QPainter *painter, const QRectF &rect, Flags flags) void ENCAtlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
{ {
AtlasData *data = _data.value(_usage); QList<Data*> data(levels());
Range zr(zooms(_usage)); Range zr(zooms(_usage));
QPointF tl(floor(rect.left() / TILE_SIZE) * TILE_SIZE, QPointF tl(floor(rect.left() / TILE_SIZE) * TILE_SIZE,
floor(rect.top() / TILE_SIZE) * TILE_SIZE); floor(rect.top() / TILE_SIZE) * TILE_SIZE);

View File

@ -74,6 +74,7 @@ private:
void cancelJobs(bool wait); void cancelJobs(bool wait);
QString key(int zoom, const QPoint &xy) const; QString key(int zoom, const QPoint &xy) const;
void addMap(const QDir &dir, const QByteArray &file, const RectC &bounds); void addMap(const QDir &dir, const QByteArray &file, const RectC &bounds);
QList<ENC::Data*> levels() const;
static bool processRecord(const ENC::ISO8211::Record &record, static bool processRecord(const ENC::ISO8211::Record &record,
QByteArray &file, RectC &bounds); QByteArray &file, RectC &bounds);

View File

@ -338,7 +338,7 @@ void ENCMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
if (QPixmapCache::find(key(_zoom, ttl), &pm)) if (QPixmapCache::find(key(_zoom, ttl), &pm))
painter->drawPixmap(ttl, pm); painter->drawPixmap(ttl, pm);
else else
tiles.append(RasterTile(_projection, _transform, _style, _data, tiles.append(RasterTile(_projection, _transform, _style, _data,
_zoom, _zooms, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _zoom, _zooms, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)),
_tileRatio)); _tileRatio));
} }