1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-07 16:02:51 +02:00

Compare commits

...

30 Commits
13.1 ... 13.3

Author SHA1 Message Date
822a0c2866 Tile search can be done lock-free 2023-05-21 09:14:19 +02:00
a92d6efec6 Do not do any time consuming actions in the mapview redraw callback
On all vector maps (ENC, IMG and Mapsforge), do the data loading
asynchronous like the tile rendering.
2023-05-19 19:33:22 +02:00
4615709b99 Merge branch 'origin/master' into Weblate. 2023-05-19 01:31:46 +02:00
8a72b20af8 Added support for all paths scaling modes 2023-05-19 01:30:54 +02:00
f86aa8c012 Merge branch 'origin/master' into Weblate. 2023-05-17 23:15:09 +02:00
e351eb6370 Only preallocate the memory when usin moveto/lineto 2023-05-17 23:10:45 +02:00
81e967f20d Only fetch data when the rect is valid 2023-05-17 23:08:17 +02:00
dbf5828e65 Merge branch 'origin/master' into Weblate. 2023-05-16 23:03:34 +02:00
cf81a90865 Some more micro-optimizations & code cleanup 2023-05-16 23:03:07 +02:00
37d408c953 Translated using Weblate (Danish)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/da/
2023-05-16 21:51:52 +02:00
61c3ed60d7 Translated using Weblate (French)
Currently translated at 99.7% (466 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2023-05-14 00:53:09 +02:00
04c203625f Version++ 2023-05-13 15:05:10 +02:00
d0cea97c90 Added support for custom HTTP headers in map tile requests 2023-05-13 15:01:35 +02:00
ddc7eb7149 Do not outline soundings like in ENC maps 2023-05-12 10:19:52 +02:00
bb22ad95b7 Use the point label as additional source for the id hash
Some (marine) maps have different points with the same type on the same
position.
2023-05-11 22:57:35 +02:00
682fcc09cc Merge branch 'origin/master' into Weblate. 2023-05-11 21:31:32 +02:00
60e83b24f9 Use as much as possible of the 64b hash in Qt6 2023-05-11 21:31:10 +02:00
c30501185c Merge branch 'origin/master' into Weblate. 2023-05-07 21:20:08 +02:00
9b3c11cc68 Version++ 2023-05-07 21:19:55 +02:00
61f77ef19e Merge branch 'origin/master' into Weblate. 2023-05-07 21:16:26 +02:00
c0834491d3 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2023-05-07 21:16:25 +02:00
e6fdd0f53d Fixed crash on empty routes 2023-05-07 21:15:44 +02:00
fe444e88a3 Merge branch 'origin/master' into Weblate. 2023-05-06 21:53:53 +02:00
d9c0770b51 Code cleanup 2023-05-06 21:53:40 +02:00
3a0e9bb733 Merge branch 'origin/master' into Weblate. 2023-05-06 16:15:14 +02:00
ca6c7247c0 Added missing cache insert 2023-05-06 16:14:49 +02:00
0b25cb9f81 Merge branch 'origin/master' into Weblate. 2023-05-04 21:49:22 +02:00
b19c3a83f3 Merge branch 'origin/master' into Weblate. 2023-05-04 09:52:05 +02:00
728361ad7b Merge branch 'origin/master' into Weblate. 2023-05-04 09:41:07 +02:00
raf
f5e3e5bd21 Translated using Weblate (Catalan)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ca/
2023-04-29 11:48:37 +02:00
51 changed files with 539 additions and 417 deletions

View File

@ -1,4 +1,4 @@
version: 13.1.{build} version: 13.3.{build}
configuration: configuration:
- Release - Release

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 13.1 VERSION = 13.3
QT += core \ QT += core \
gui \ gui \

View File

@ -866,7 +866,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/> <location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/> <location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source> <source>CRS directory:</source>
<translation type="unfinished"></translation> <translation>Directori CRS:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="909"/> <location filename="../src/GUI/gui.cpp" line="909"/>
@ -1020,6 +1020,7 @@
<translation> <translation>
<numerusform>%n fitxer</numerusform> <numerusform>%n fitxer</numerusform>
<numerusform>%n fitxers</numerusform> <numerusform>%n fitxers</numerusform>
<numerusform>%n fitxers</numerusform>
</translation> </translation>
</message> </message>
</context> </context>

View File

@ -712,7 +712,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/> <location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/> <location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source> <source>CRS directory:</source>
<translation type="unfinished"></translation> <translation>CRS-katalog:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="913"/> <location filename="../src/GUI/gui.cpp" line="913"/>

View File

@ -958,7 +958,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/> <location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/> <location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source> <source>CRS directory:</source>
<translation type="unfinished"></translation> <translation>Dossier CRS:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="915"/> <location filename="../src/GUI/gui.cpp" line="915"/>
@ -1427,12 +1427,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="70"/> <location filename="../src/GUI/optionsdialog.cpp" line="70"/>
<source>Select the proper coordinate reference system (CRS) of maps without a CRS definition (JNX, KMZ and World file maps).</source> <source>Select the proper coordinate reference system (CRS) of maps without a CRS definition (JNX, KMZ and World file maps).</source>
<translation type="unfinished"></translation> <translation type="unfinished">Sélectionnez le système de référence de coordonnée (CRS) approprié pour les cartes sans définition de CRS (JNX, KMZ et World file maps).</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="73"/> <location filename="../src/GUI/optionsdialog.cpp" line="73"/>
<source>Select the desired projection of vector maps (IMG, Mapsforge and ENC maps). The projection must be valid for the whole map area.</source> <source>Select the desired projection of vector maps (IMG, Mapsforge and ENC maps). The projection must be valid for the whole map area.</source>
<translation type="unfinished"></translation> <translation>Sélectionnez la projection désirée de la carte vectorielle (IMG, Mapsforge et carte ENC). La projection doit être valide pour la totalité de la zone de la carte.</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="77"/> <location filename="../src/GUI/optionsdialog.cpp" line="77"/>
@ -1912,7 +1912,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="758"/> <location filename="../src/GUI/optionsdialog.cpp" line="758"/>
<source>DEM cache size:</source> <source>DEM cache size:</source>
<translation type="unfinished"></translation> <translation>Taille du cache DEM :</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="778"/> <location filename="../src/GUI/optionsdialog.cpp" line="778"/>

View File

@ -712,7 +712,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/> <location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/> <location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source> <source>CRS directory:</source>
<translation type="unfinished"></translation> <translation>CRS-mappe:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="913"/> <location filename="../src/GUI/gui.cpp" line="913"/>
@ -1718,12 +1718,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="70"/> <location filename="../src/GUI/optionsdialog.cpp" line="70"/>
<source>Select the proper coordinate reference system (CRS) of maps without a CRS definition (JNX, KMZ and World file maps).</source> <source>Select the proper coordinate reference system (CRS) of maps without a CRS definition (JNX, KMZ and World file maps).</source>
<translation type="unfinished"></translation> <translation>Velg riktig koordinatreferansesystem (CRS) for kart uten en CRS-definisjon (JNX, KMZ og World-file kart).</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="73"/> <location filename="../src/GUI/optionsdialog.cpp" line="73"/>
<source>Select the desired projection of vector maps (IMG, Mapsforge and ENC maps). The projection must be valid for the whole map area.</source> <source>Select the desired projection of vector maps (IMG, Mapsforge and ENC maps). The projection must be valid for the whole map area.</source>
<translation type="unfinished"></translation> <translation>Velg ønsket projeksjon for vektorkart (IMG, Mapsforge og ENC-kart). Projeksjonen være gyldig for hele kartområdet.</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="104"/> <location filename="../src/GUI/optionsdialog.cpp" line="104"/>

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.1" !define VERSION "13.3"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -3,6 +3,7 @@
#include <cmath> #include <cmath>
#include <QDebug> #include <QDebug>
#include "hash.h"
#define deg2rad(d) (((d)*M_PI)/180.0) #define deg2rad(d) (((d)*M_PI)/180.0)
#define rad2deg(d) (((d)*180.0)/M_PI) #define rad2deg(d) (((d)*180.0)/M_PI)
@ -48,6 +49,11 @@ inline bool operator<(const Coordinates &c1, const Coordinates &c2)
return (c1.lat() < c2.lat()); return (c1.lat() < c2.lat());
} }
inline HASH_T qHash(const Coordinates &c)
{
return qHash(QPair<double, double>(c.lon(), c.lat()));
}
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Coordinates &c); QDebug operator<<(QDebug dbg, const Coordinates &c);
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -53,7 +53,7 @@ Authorization::Authorization(const QString &username, const QString &password)
{ {
QString concatenated = username + ":" + password; QString concatenated = username + ":" + password;
QByteArray data = concatenated.toLocal8Bit().toBase64(); QByteArray data = concatenated.toLocal8Bit().toBase64();
_header = "Basic " + data; _header = HTTPHeader("Authorization", "Basic " + data);
} }
NetworkTimeout::NetworkTimeout(int timeout, QNetworkReply *reply) NetworkTimeout::NetworkTimeout(int timeout, QNetworkReply *reply)
@ -83,9 +83,10 @@ QNetworkAccessManager *Downloader::_manager = 0;
int Downloader::_timeout = 30; int Downloader::_timeout = 30;
bool Downloader::_http2 = true; bool Downloader::_http2 = true;
bool Downloader::doDownload(const Download &dl, const Authorization &auth) bool Downloader::doDownload(const Download &dl, const QList<HTTPHeader> &headers)
{ {
const QUrl &url = dl.url(); const QUrl &url = dl.url();
bool userAgent = false;
if (!url.isValid() || !(url.scheme() == QLatin1String("http") if (!url.isValid() || !(url.scheme() == QLatin1String("http")
|| url.scheme() == QLatin1String("https"))) { || url.scheme() == QLatin1String("https"))) {
@ -103,9 +104,15 @@ bool Downloader::doDownload(const Download &dl, const Authorization &auth)
request.setAttribute(ATTR_REDIRECT_POLICY, request.setAttribute(ATTR_REDIRECT_POLICY,
QNetworkRequest::NoLessSafeRedirectPolicy); QNetworkRequest::NoLessSafeRedirectPolicy);
request.setAttribute(ATTR_HTTP2_ALLOWED, QVariant(_http2)); request.setAttribute(ATTR_HTTP2_ALLOWED, QVariant(_http2));
request.setRawHeader("User-Agent", USER_AGENT);
if (!auth.isNull()) for (int i = 0; i < headers.size(); i++) {
request.setRawHeader("Authorization", auth.header()); const HTTPHeader &hdr = headers.at(i);
request.setRawHeader(hdr.key(), hdr.value());
if (hdr.key() == "User-Agent")
userAgent = true;
}
if (!userAgent)
request.setRawHeader("User-Agent", USER_AGENT);
QFile *file = new QFile(tmpName(dl.file())); QFile *file = new QFile(tmpName(dl.file()));
if (!file->open(QIODevice::WriteOnly)) { if (!file->open(QIODevice::WriteOnly)) {
@ -183,12 +190,12 @@ void Downloader::downloadFinished(QNetworkReply *reply)
} }
bool Downloader::get(const QList<Download> &list, bool Downloader::get(const QList<Download> &list,
const Authorization &authorization) const QList<HTTPHeader> &headers)
{ {
bool finishEmitted = false; bool finishEmitted = false;
for (int i = 0; i < list.count(); i++) for (int i = 0; i < list.count(); i++)
finishEmitted |= doDownload(list.at(i), authorization); finishEmitted |= doDownload(list.at(i), headers);
return finishEmitted; return finishEmitted;
} }

View File

@ -7,9 +7,12 @@
#include <QUrl> #include <QUrl>
#include <QList> #include <QList>
#include <QHash> #include <QHash>
#include "common/kv.h"
class QFile; class QFile;
typedef KV<QByteArray, QByteArray> HTTPHeader;
class Download class Download
{ {
public: public:
@ -29,11 +32,11 @@ public:
Authorization() {} Authorization() {}
Authorization(const QString &username, const QString &password); Authorization(const QString &username, const QString &password);
bool isNull() const {return _header.isNull();} const HTTPHeader &header() const {return _header;}
const QByteArray &header() const {return _header;} bool isNull() const {return _header.key().isNull();}
private: private:
QByteArray _header; HTTPHeader _header;
}; };
class NetworkTimeout : public QObject class NetworkTimeout : public QObject
@ -60,8 +63,7 @@ class Downloader : public QObject
public: public:
Downloader(QObject *parent = 0) : QObject(parent) {} Downloader(QObject *parent = 0) : QObject(parent) {}
bool get(const QList<Download> &list, const Authorization &authorization bool get(const QList<Download> &list, const QList<HTTPHeader> &headers);
= Authorization());
void clearErrors() {_errorDownloads.clear();} void clearErrors() {_errorDownloads.clear();}
static void setNetworkManager(QNetworkAccessManager *manager) static void setNetworkManager(QNetworkAccessManager *manager)
@ -80,7 +82,7 @@ private:
class ReplyTimeout; class ReplyTimeout;
void insertError(const QUrl &url, QNetworkReply::NetworkError error); void insertError(const QUrl &url, QNetworkReply::NetworkError error);
bool doDownload(const Download &dl, const Authorization &auth); bool doDownload(const Download &dl, const QList<HTTPHeader> &headers);
void downloadFinished(QNetworkReply *reply); void downloadFinished(QNetworkReply *reply);
void readData(QNetworkReply *reply); void readData(QNetworkReply *reply);

View File

@ -6,13 +6,13 @@
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#define HASH_T uint #define HASH_T uint
inline uint qHash(const QPoint &p)
{
return qHash(QPair<int, int>(p.x(), p.y()));
}
#else // QT6 #else // QT6
#define HASH_T size_t #define HASH_T size_t
#endif // QT6 #endif // QT6
inline HASH_T qHash(const QPoint &p)
{
return ::qHash(p.x()) ^ ::qHash(p.y());
}
#endif // HASH_H #endif // HASH_H

View File

@ -4,6 +4,7 @@
template <class KEY, class VALUE> template <class KEY, class VALUE>
class KV { class KV {
public: public:
KV() {}
KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {} KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {}
const KEY &key() const {return _key;} const KEY &key() const {return _key;}

View File

@ -64,7 +64,7 @@ bool DEMLoader::loadTiles(const RectC &rect)
} }
} }
return _downloader->get(dl, _authorization); return _downloader->get(dl, _headers);
} }
bool DEMLoader::checkTiles(const RectC &rect) const bool DEMLoader::checkTiles(const RectC &rect) const
@ -97,3 +97,11 @@ QString DEMLoader::tileFile(const DEM::Tile &tile) const
{ {
return _dir.absoluteFilePath(tile.baseName()); return _dir.absoluteFilePath(tile.baseName());
} }
void DEMLoader::setAuthorization(const Authorization &authorization)
{
QList<HTTPHeader> headers;
if (!authorization.isNull())
headers.append(authorization.header());
_headers = headers;
}

View File

@ -16,8 +16,7 @@ public:
DEMLoader(const QString &dir, QObject *parent = 0); DEMLoader(const QString &dir, QObject *parent = 0);
void setUrl(const QString &url) {_url = url;} void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization) void setAuthorization(const Authorization &authorization);
{_authorization = authorization;}
bool loadTiles(const RectC &rect); bool loadTiles(const RectC &rect);
bool checkTiles(const RectC &rect) const; bool checkTiles(const RectC &rect) const;
@ -34,7 +33,7 @@ private:
Downloader *_downloader; Downloader *_downloader;
QString _url; QString _url;
QDir _dir; QDir _dir;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };
#endif // DEMLOADER_H #endif // DEMLOADER_H

View File

@ -33,13 +33,16 @@ Path Route::path() const
Graph Route::gpsElevation() const Graph Route::gpsElevation() const
{ {
Graph graph; Graph graph;
graph.append(GraphSegment(QDateTime())); QDateTime date;
GraphSegment &gs = graph.last(); GraphSegment gs(date);
for (int i = 0; i < _data.size(); i++) for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation()) if (_data.at(i).hasElevation())
gs.append(GraphPoint(_distance.at(i), NAN, _data.at(i).elevation())); gs.append(GraphPoint(_distance.at(i), NAN, _data.at(i).elevation()));
if (gs.size() >= 2)
graph.append(gs);
if (_data.style().color().isValid()) if (_data.style().color().isValid())
graph.setColor(_data.style().color()); graph.setColor(_data.style().color());
@ -49,8 +52,8 @@ Graph Route::gpsElevation() const
Graph Route::demElevation() const Graph Route::demElevation() const
{ {
Graph graph; Graph graph;
graph.append(GraphSegment(QDateTime())); QDateTime date;
GraphSegment &gs = graph.last(); GraphSegment gs(date);
for (int i = 0; i < _data.size(); i++) { for (int i = 0; i < _data.size(); i++) {
qreal dem = DEM::elevation(_data.at(i).coordinates()); qreal dem = DEM::elevation(_data.at(i).coordinates());
@ -58,6 +61,9 @@ Graph Route::demElevation() const
gs.append(GraphPoint(_distance.at(i), NAN, dem)); gs.append(GraphPoint(_distance.at(i), NAN, dem));
} }
if (gs.size() >= 2)
graph.append(gs);
if (_data.style().color().isValid()) if (_data.style().color().isValid())
graph.setColor(_data.style().color()); graph.setColor(_data.style().color());

View File

@ -893,7 +893,7 @@ void MapData::clear()
_points.RemoveAll(); _points.RemoveAll();
} }
void MapData::points(const RectC &rect, QList<Point*> *points) void MapData::points(const RectC &rect, QList<Point*> *points) const
{ {
double min[2], max[2]; double min[2], max[2];
@ -901,7 +901,7 @@ void MapData::points(const RectC &rect, QList<Point*> *points)
_points.Search(min, max, pointCb, points); _points.Search(min, max, pointCb, points);
} }
void MapData::lines(const RectC &rect, QList<Line*> *lines) void MapData::lines(const RectC &rect, QList<Line*> *lines) const
{ {
double min[2], max[2]; double min[2], max[2];
@ -909,7 +909,7 @@ void MapData::lines(const RectC &rect, QList<Line*> *lines)
_lines.Search(min, max, lineCb, lines); _lines.Search(min, max, lineCb, lines);
} }
void MapData::polygons(const RectC &rect, QList<Poly*> *polygons) void MapData::polygons(const RectC &rect, QList<Poly*> *polygons) const
{ {
double min[2], max[2]; double min[2], max[2];

View File

@ -72,9 +72,9 @@ public:
RectC bounds() const {return _bounds;} RectC bounds() const {return _bounds;}
Range zooms() const; Range zooms() const;
void polygons(const RectC &rect, QList<Poly*> *polygons); void polygons(const RectC &rect, QList<Poly*> *polygons) const;
void lines(const RectC &rect, QList<Line*> *lines); void lines(const RectC &rect, QList<Line*> *lines) const;
void points(const RectC &rect, QList<Point*> *points); void points(const RectC &rect, QList<Point*> *points) const;
void load(); void load();
void clear(); void clear();

View File

@ -3,11 +3,14 @@
#include "common/linec.h" #include "common/linec.h"
#include "map/bitmapline.h" #include "map/bitmapline.h"
#include "map/textpathitem.h" #include "map/textpathitem.h"
#include "map/rectd.h"
#include "style.h" #include "style.h"
#include "rastertile.h" #include "rastertile.h"
using namespace ENC; using namespace ENC;
#define TEXT_EXTENT 160
#define TSSLPT_SIZE 0.005 /* ll */ #define TSSLPT_SIZE 0.005 /* ll */
#define RDOCAL_SIZE 12 /* px */ #define RDOCAL_SIZE 12 /* px */
#define CURENT_SIZE 12 /* px */ #define CURENT_SIZE 12 /* px */
@ -227,10 +230,11 @@ QPolygonF RasterTile::tsslptArrow(const Coordinates &c, qreal angle) const
return polygon; return polygon;
} }
void RasterTile::drawArrows(QPainter *painter) void RasterTile::drawArrows(QPainter *painter,
const QList<MapData::Poly*> &polygons)
{ {
for (int i = 0; i < _polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly *poly = _polygons.at(i); const MapData::Poly *poly = polygons.at(i);
if (poly->type()>>16 == TSSLPT) { if (poly->type()>>16 == TSSLPT) {
QPolygonF polygon(tsslptArrow(centroid(poly->path().first()), QPolygonF polygon(tsslptArrow(centroid(poly->path().first()),
@ -243,13 +247,14 @@ void RasterTile::drawArrows(QPainter *painter)
} }
} }
void RasterTile::drawPolygons(QPainter *painter) void RasterTile::drawPolygons(QPainter *painter,
const QList<MapData::Poly*> &polygons)
{ {
const Style &s = style(); const Style &s = style();
for (int n = 0; n < s.drawOrder().size(); n++) { for (int n = 0; n < s.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 MapData::Poly *poly = polygons.at(i);
if (poly->type() != s.drawOrder().at(n)) if (poly->type() != s.drawOrder().at(n))
continue; continue;
const Style::Polygon &style = s.polygon(poly->type()); const Style::Polygon &style = s.polygon(poly->type());
@ -267,14 +272,14 @@ void RasterTile::drawPolygons(QPainter *painter)
} }
} }
void RasterTile::drawLines(QPainter *painter) void RasterTile::drawLines(QPainter *painter, const QList<MapData::Line*> &lines)
{ {
const Style &s = style(); const Style &s = style();
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 MapData::Line *line = lines.at(i);
const Style::Line &style = s.line(line->type()); const Style::Line &style = s.line(line->type());
if (!style.img().isNull()) { if (!style.img().isNull()) {
@ -293,12 +298,13 @@ void RasterTile::drawTextItems(QPainter *painter,
textItems.at(i)->paint(painter); textItems.at(i)->paint(painter);
} }
void RasterTile::processPolygons(QList<TextItem*> &textItems) void RasterTile::processPolygons(const QList<MapData::Poly*> &polygons,
QList<TextItem*> &textItems)
{ {
const Style &s = style(); const Style &s = style();
for (int i = 0; i < _polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly *poly = _polygons.at(i); const MapData::Poly *poly = polygons.at(i);
uint type = poly->type()>>16; uint type = poly->type()>>16;
if (!(type == HRBFAC || type == I_TRNBSN if (!(type == HRBFAC || type == I_TRNBSN
@ -319,18 +325,18 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
} }
} }
void RasterTile::processPoints(QList<TextItem*> &textItems, void RasterTile::processPoints(QList<MapData::Point*> &points,
QList<TextItem*> &lights) QList<TextItem*> &textItems, QList<TextItem*> &lights)
{ {
const Style &s = style(); const Style &s = style();
PointMap lightsMap, signalsMap; PointMap lightsMap, signalsMap;
int i; int i;
std::sort(_points.begin(), _points.end(), pointLess); std::sort(points.begin(), points.end(), pointLess);
/* 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 MapData::Point *point = points.at(i);
if (point->type()>>16 == LIGHTS) if (point->type()>>16 == LIGHTS)
lightsMap.insert(point->pos(), point); lightsMap.insert(point->pos(), point);
else if (point->type()>>16 == FOGSIG) else if (point->type()>>16 == FOGSIG)
@ -340,8 +346,8 @@ void RasterTile::processPoints(QList<TextItem*> &textItems,
} }
/* Everything else */ /* Everything else */
for ( ; i < _points.size(); i++) { for ( ; i < points.size(); i++) {
const MapData::Point *point = _points.at(i); const MapData::Point *point = points.at(i);
QPoint pos(ll2xy(point->pos()).toPoint()); QPoint pos(ll2xy(point->pos()).toPoint());
const Style::Point &style = s.point(point->type()); const Style::Point &style = s.point(point->type());
@ -349,7 +355,7 @@ void RasterTile::processPoints(QList<TextItem*> &textItems,
QImage *rimg = style.img().isNull() QImage *rimg = style.img().isNull()
? image(point->type(), point->param()) : 0; ? image(point->type(), point->param()) : 0;
const QImage *img = style.img().isNull() ? rimg : &style.img(); const QImage *img = style.img().isNull() ? rimg : &style.img();
const QFont *fnt = showLabel(img, _zooms, _zoom, point->type()) const QFont *fnt = showLabel(img, _data->zooms(), _zoom, point->type())
? font(style.textFontSize()) : 0; ? 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()
@ -371,12 +377,13 @@ void RasterTile::processPoints(QList<TextItem*> &textItems,
} }
} }
void RasterTile::processLines(QList<TextItem*> &textItems) void RasterTile::processLines(const QList<MapData::Line*> &lines,
QList<TextItem*> &textItems)
{ {
const Style &s = style(); const Style &s = style();
for (int i = 0; i < _lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Line *line = _lines.at(i); const MapData::Line *line = lines.at(i);
const Style::Line &style = s.line(line->type()); const Style::Line &style = s.line(line->type());
if (style.img().isNull() && style.pen() == Qt::NoPen) if (style.img().isNull() && style.pen() == Qt::NoPen)
@ -396,25 +403,51 @@ void RasterTile::processLines(QList<TextItem*> &textItems)
} }
} }
void RasterTile::fetchData(QList<MapData::Poly*> &polygons,
QList<MapData::Line*> &lines, QList<MapData::Point*> &points)
{
QPoint ttl(_rect.topLeft());
QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y()
+ _rect.height()));
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
RectC polyRectC(polyRectD.toRectC(_proj, 20));
_data->lines(polyRectC, &lines);
_data->polygons(polyRectC, &polygons);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()
+ TEXT_EXTENT));
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data->points(pointRectD.toRectC(_proj, 20), &points);
}
void RasterTile::render() void RasterTile::render()
{ {
QList<MapData::Line*> lines;
QList<MapData::Poly*> polygons;
QList<MapData::Point*> points;
QList<TextItem*> textItems, lights; QList<TextItem*> textItems, lights;
_pixmap.setDevicePixelRatio(_ratio); _pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent); _pixmap.fill(Qt::transparent);
processPolygons(textItems); fetchData(polygons, lines, points);
processPoints(textItems, lights);
processLines(textItems); processPolygons(polygons, textItems);
processPoints(points, textItems, lights);
processLines(lines, textItems);
QPainter painter(&_pixmap); QPainter painter(&_pixmap);
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); drawPolygons(&painter, polygons);
drawLines(&painter); drawLines(&painter, lines);
drawArrows(&painter); drawArrows(&painter, polygons);
drawTextItems(&painter, lights); drawTextItems(&painter, lights);
drawTextItems(&painter, textItems); drawTextItems(&painter, textItems);

View File

@ -15,13 +15,10 @@ class RasterTile
{ {
public: public:
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Range &zooms, int zoom, const QRect &rect, qreal ratio, const MapData *data, int zoom, const QRect &rect, qreal ratio)
const QList<MapData::Line*> &lines, const QList<MapData::Poly*> &polygons, : _proj(proj), _transform(transform), _data(data), _zoom(zoom),
const QList<MapData::Point*> &points)
: _proj(proj), _transform(transform), _zooms(zooms), _zoom(zoom),
_rect(rect), _ratio(ratio), _rect(rect), _ratio(ratio),
_pixmap(rect.width() * ratio, rect.height() * ratio), _lines(lines), _pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
_polygons(polygons), _points(points), _valid(false) {}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
QPoint xy() const {return _rect.topLeft();} QPoint xy() const {return _rect.topLeft();}
@ -44,31 +41,33 @@ private:
const QImage *_rimg; const QImage *_rimg;
}; };
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;
QPolygonF polyline(const QVector<Coordinates> &path) const; QPolygonF polyline(const QVector<Coordinates> &path) const;
QPolygonF tsslptArrow(const Coordinates &c, qreal angle) const; QPolygonF tsslptArrow(const Coordinates &c, qreal angle) const;
void processPoints(QList<TextItem*> &textItems, QList<TextItem *> &lights); void processPoints(QList<MapData::Point *> &points,
void processLines(QList<TextItem*> &textItems); QList<TextItem*> &textItems, QList<TextItem *> &lights);
void processPolygons(QList<TextItem*> &textItems); void processLines(const QList<MapData::Line *> &lines,
QList<TextItem*> &textItems);
void processPolygons(const QList<MapData::Poly *> &polygons,
QList<TextItem*> &textItems);
void drawBitmapPath(QPainter *painter, const QImage &img, void drawBitmapPath(QPainter *painter, const QImage &img,
const Polygon &polygon); const Polygon &polygon);
void drawArrows(QPainter *painter); void drawArrows(QPainter *painter, const QList<MapData::Poly*> &polygons);
void drawPolygons(QPainter *painter); void drawPolygons(QPainter *painter, const QList<MapData::Poly *> &polygons);
void drawLines(QPainter *painter); void drawLines(QPainter *painter, const QList<MapData::Line *> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems); void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
Range _zooms; const MapData *_data;
int _zoom; int _zoom;
QRect _rect; QRect _rect;
qreal _ratio; qreal _ratio;
QPixmap _pixmap; QPixmap _pixmap;
QList<MapData::Line*> _lines;
QList<MapData::Poly*> _polygons;
QList<MapData::Point*> _points;
bool _valid; bool _valid;
}; };

View File

@ -13,14 +13,14 @@ bool MapData::polyCb(VectorTile *tile, void *context)
{ {
PolyCTX *ctx = (PolyCTX*)context; PolyCTX *ctx = (PolyCTX*)context;
tile->polys(ctx->rect, ctx->zoom, ctx->polygons, ctx->lines, tile->polys(ctx->rect, ctx->zoom, ctx->polygons, ctx->lines,
ctx->polyCache); ctx->polyCache, ctx->lock);
return true; return true;
} }
bool MapData::pointCb(VectorTile *tile, void *context) bool MapData::pointCb(VectorTile *tile, void *context)
{ {
PointCTX *ctx = (PointCTX*)context; PointCTX *ctx = (PointCTX*)context;
tile->points(ctx->rect, ctx->zoom, ctx->points, ctx->pointCache); tile->points(ctx->rect, ctx->zoom, ctx->points, ctx->pointCache, ctx->lock);
return true; return true;
} }
@ -45,7 +45,7 @@ MapData::~MapData()
void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons, void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines) QList<Poly> *lines)
{ {
PolyCTX ctx(rect, zoom(bits), polygons, lines, &_polyCache); PolyCTX ctx(rect, zoom(bits), polygons, lines, &_polyCache, &_lock);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();
@ -58,7 +58,7 @@ void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
void MapData::points(const RectC &rect, int bits, QList<Point> *points) void MapData::points(const RectC &rect, int bits, QList<Point> *points)
{ {
PointCTX ctx(rect, zoom(bits), points, &_pointCache); PointCTX ctx(rect, zoom(bits), points, &_pointCache, &_lock);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();

View File

@ -4,6 +4,7 @@
#include <QList> #include <QList>
#include <QPointF> #include <QPointF>
#include <QCache> #include <QCache>
#include <QMutex>
#include <QDebug> #include <QDebug>
#include "common/rectc.h" #include "common/rectc.h"
#include "common/rtree.h" #include "common/rtree.h"
@ -97,32 +98,37 @@ private:
QList<Poly> lines; QList<Poly> lines;
}; };
typedef QCache<const SubDiv*, Polys> PolyCache;
typedef QCache<const SubDiv*, QList<Point> > PointCache;
struct PolyCTX struct PolyCTX
{ {
PolyCTX(const RectC &rect, const Zoom &zoom, PolyCTX(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv*, MapData::Polys> *polyCache) PolyCache *polyCache, QMutex *lock)
: rect(rect), zoom(zoom), polygons(polygons), lines(lines), : rect(rect), zoom(zoom), polygons(polygons), lines(lines),
polyCache(polyCache) {} polyCache(polyCache), lock(lock) {}
const RectC &rect; const RectC &rect;
const Zoom &zoom; const Zoom &zoom;
QList<MapData::Poly> *polygons; QList<MapData::Poly> *polygons;
QList<MapData::Poly> *lines; QList<MapData::Poly> *lines;
QCache<const SubDiv*, MapData::Polys> *polyCache; PolyCache *polyCache;
QMutex *lock;
}; };
struct PointCTX struct PointCTX
{ {
PointCTX(const RectC &rect, const Zoom &zoom, PointCTX(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QList<MapData::Point> *points, PointCache *pointCache, QMutex *lock)
QCache<const SubDiv*, QList<MapData::Point> > *pointCache) : rect(rect), zoom(zoom), points(points), pointCache(pointCache),
: rect(rect), zoom(zoom), points(points), pointCache(pointCache) {} lock(lock) {}
const RectC &rect; const RectC &rect;
const Zoom &zoom; const Zoom &zoom;
QList<MapData::Point> *points; QList<MapData::Point> *points;
QCache<const SubDiv*, QList<MapData::Point> > *pointCache; PointCache *pointCache;
QMutex *lock;
}; };
const Zoom &zoom(int bits) const; const Zoom &zoom(int bits) const;
@ -130,8 +136,9 @@ private:
static bool polyCb(VectorTile *tile, void *context); static bool polyCb(VectorTile *tile, void *context);
static bool pointCb(VectorTile *tile, void *context); static bool pointCb(VectorTile *tile, void *context);
QCache<const SubDiv*, Polys> _polyCache; PolyCache _polyCache;
QCache<const SubDiv*, QList<Point> > _pointCache; PointCache _pointCache;
QMutex _lock;
friend class VectorTile; friend class VectorTile;
}; };

View File

@ -5,12 +5,14 @@
#include "map/textpathitem.h" #include "map/textpathitem.h"
#include "map/textpointitem.h" #include "map/textpointitem.h"
#include "map/bitmapline.h" #include "map/bitmapline.h"
#include "map/rectd.h"
#include "style.h" #include "style.h"
#include "lblfile.h" #include "lblfile.h"
#include "rastertile.h" #include "rastertile.h"
using namespace IMG; using namespace IMG;
#define TEXT_EXTENT 160
#define ICON_PADDING 2 #define ICON_PADDING 2
#define AREA(rect) \ #define AREA(rect) \
@ -147,40 +149,6 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|| polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill))); || polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill)));
} }
void RasterTile::render()
{
QList<TextItem*> textItems;
ll2xy(_polygons);
ll2xy(_lines);
ll2xy(_points);
processPoints(textItems);
processPolygons(textItems);
processLines(textItems);
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y());
drawPolygons(&painter);
drawLines(&painter);
drawTextItems(&painter, textItems);
qDeleteAll(textItems);
_valid = true;
//painter.setPen(Qt::red);
//painter.setRenderHint(QPainter::Antialiasing, false);
//painter.drawRect(QRect(_xy, _pixmap.size()));
}
void RasterTile::ll2xy(QList<MapData::Poly> &polys) void RasterTile::ll2xy(QList<MapData::Poly> &polys)
{ {
for (int i = 0; i < polys.size(); i++) { for (int i = 0; i < polys.size(); i++) {
@ -200,14 +168,15 @@ void RasterTile::ll2xy(QList<MapData::Point> &points)
} }
} }
void RasterTile::drawPolygons(QPainter *painter) void RasterTile::drawPolygons(QPainter *painter,
const QList<MapData::Poly> &polygons)
{ {
QCache<const LBLFile *, SubFile::Handle> hc(16); QCache<const LBLFile *, SubFile::Handle> hc(16);
for (int n = 0; n < _style->drawOrder().size(); n++) { for (int n = 0; n < _data->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 MapData::Poly &poly = polygons.at(i);
if (poly.type != _style->drawOrder().at(n)) if (poly.type != _data->style()->drawOrder().at(n))
continue; continue;
if (poly.raster.isValid()) { if (poly.raster.isValid()) {
@ -237,7 +206,7 @@ void RasterTile::drawPolygons(QPainter *painter)
//painter->setBrush(Qt::NoBrush); //painter->setBrush(Qt::NoBrush);
//painter->drawRect(QRectF(tl, br)); //painter->drawRect(QRectF(tl, br));
} else { } else {
const Style::Polygon &style = _style->polygon(poly.type); const Style::Polygon &style = _data->style()->polygon(poly.type);
painter->setPen(style.pen()); painter->setPen(style.pen());
painter->setBrush(style.brush()); painter->setBrush(style.brush());
@ -247,13 +216,13 @@ void RasterTile::drawPolygons(QPainter *painter)
} }
} }
void RasterTile::drawLines(QPainter *painter) void RasterTile::drawLines(QPainter *painter, const QList<MapData::Poly> &lines)
{ {
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::Poly &poly = _lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _style->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.background() == Qt::NoPen) if (style.background() == Qt::NoPen)
continue; continue;
@ -262,9 +231,9 @@ void RasterTile::drawLines(QPainter *painter)
painter->drawPolyline(poly.points); painter->drawPolyline(poly.points);
} }
for (int i = 0; i < _lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _style->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (!style.img().isNull()) if (!style.img().isNull())
BitmapLine::draw(painter, poly.points, style.img()); BitmapLine::draw(painter, poly.points, style.img());
@ -295,13 +264,14 @@ static void removeDuplicitLabel(QList<TextItem *> &labels, const QString &text,
} }
} }
void RasterTile::processPolygons(QList<TextItem*> &textItems) void RasterTile::processPolygons(const QList<MapData::Poly> &polygons,
QList<TextItem*> &textItems)
{ {
QSet<QString> set; QSet<QString> set;
QList<TextItem *> labels; QList<TextItem *> labels;
for (int i = 0; i < _polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly &poly = _polygons.at(i); const MapData::Poly &poly = polygons.at(i);
bool exists = set.contains(poly.label.text()); bool exists = set.contains(poly.label.text());
if (poly.label.text().isEmpty()) if (poly.label.text().isEmpty())
@ -310,7 +280,7 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
if (_zoom <= 23 && (Style::isWaterArea(poly.type) if (_zoom <= 23 && (Style::isWaterArea(poly.type)
|| Style::isMilitaryArea(poly.type) || Style::isMilitaryArea(poly.type)
|| Style::isNatureReserve(poly.type))) { || Style::isNatureReserve(poly.type))) {
const Style::Polygon &style = _style->polygon(poly.type); const Style::Polygon &style = _data->style()->polygon(poly.type);
TextPointItem *item = new TextPointItem( TextPointItem *item = new TextPointItem(
centroid(poly.points).toPoint(), &poly.label.text(), poiFont(), centroid(poly.points).toPoint(), &poly.label.text(), poiFont(),
0, &style.brush().color(), &haloColor); 0, &style.brush().color(), &haloColor);
@ -331,20 +301,22 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
textItems.append(labels); textItems.append(labels);
} }
void RasterTile::processLines(QList<TextItem*> &textItems) void RasterTile::processLines(QList<MapData::Poly> &lines,
QList<TextItem*> &textItems)
{ {
std::stable_sort(_lines.begin(), _lines.end()); std::stable_sort(lines.begin(), lines.end());
if (_zoom >= 22) if (_zoom >= 22)
processStreetNames(textItems); processStreetNames(lines, textItems);
processShields(textItems); processShields(lines, textItems);
} }
void RasterTile::processStreetNames(QList<TextItem*> &textItems) void RasterTile::processStreetNames(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems)
{ {
for (int i = 0; i < _lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _style->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.img().isNull() && style.foreground() == Qt::NoPen) if (style.img().isNull() && style.foreground() == Qt::NoPen)
continue; continue;
@ -366,7 +338,8 @@ void RasterTile::processStreetNames(QList<TextItem*> &textItems)
} }
} }
void RasterTile::processShields(QList<TextItem*> &textItems) void RasterTile::processShields(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems)
{ {
for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) { for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) {
if (minShieldZoom(static_cast<Shield::Type>(type)) > _zoom) if (minShieldZoom(static_cast<Shield::Type>(type)) > _zoom)
@ -375,8 +348,8 @@ void RasterTile::processShields(QList<TextItem*> &textItems)
QHash<Shield, QPolygonF> shields; QHash<Shield, QPolygonF> shields;
QHash<Shield, const Shield*> sp; QHash<Shield, const Shield*> sp;
for (int i = 0; i < _lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i); const MapData::Poly &poly = lines.at(i);
const Shield &shield = poly.label.shield(); const Shield &shield = poly.label.shield();
if (!shield.isValid() || shield.type() != type if (!shield.isValid() || shield.type() != type
|| !Style::isMajorRoad(poly.type)) || !Style::isMajorRoad(poly.type))
@ -429,13 +402,14 @@ void RasterTile::processShields(QList<TextItem*> &textItems)
} }
} }
void RasterTile::processPoints(QList<TextItem*> &textItems) void RasterTile::processPoints(QList<MapData::Point> &points,
QList<TextItem*> &textItems)
{ {
std::sort(_points.begin(), _points.end()); std::sort(points.begin(), points.end());
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = _points.at(i); const MapData::Point &point = points.at(i);
const Style::Point &style = _style->point(point.type); const Style::Point &style = _data->style()->point(point.type);
bool poi = Style::isPOI(point.type); bool poi = Style::isPOI(point.type);
const QString *label = point.label.text().isEmpty() const QString *label = point.label.text().isEmpty()
@ -446,12 +420,14 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
: font(style.textFontSize()); : font(style.textFontSize());
const QColor *color = style.textColor().isValid() const QColor *color = style.textColor().isValid()
? &style.textColor() : &textColor; ? &style.textColor() : &textColor;
const QColor *hcolor = Style::isDepthPoint(point.type)
? 0 : &haloColor;
if ((!label || !fnt) && !img) if ((!label || !fnt) && !img)
continue; continue;
TextPointItem *item = new TextPointItem(QPoint(point.coordinates.lon(), TextPointItem *item = new TextPointItem(QPoint(point.coordinates.lon(),
point.coordinates.lat()), label, fnt, img, color, &haloColor, 0, point.coordinates.lat()), label, fnt, img, color, hcolor, 0,
ICON_PADDING); ICON_PADDING);
if (item->isValid() && !item->collides(textItems)) if (item->isValid() && !item->collides(textItems))
textItems.append(item); textItems.append(item);
@ -459,3 +435,60 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
delete item; delete item;
} }
} }
void RasterTile::fetchData(QList<MapData::Poly> &polygons,
QList<MapData::Poly> &lines, QList<MapData::Point> &points)
{
QPoint ttl(_rect.topLeft());
QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y()
+ _rect.height()));
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
_data->polys(polyRectD.toRectC(_proj, 20), _zoom,
&polygons, &lines);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()
+ TEXT_EXTENT));
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data->points(pointRectD.toRectC(_proj, 20), _zoom, &points);
}
void RasterTile::render()
{
QList<MapData::Poly> polygons;
QList<MapData::Poly> lines;
QList<MapData::Point> points;
QList<TextItem*> textItems;
fetchData(polygons, lines, points);
ll2xy(polygons);
ll2xy(lines);
ll2xy(points);
processPoints(points, textItems);
processPolygons(polygons, textItems);
processLines(lines, textItems);
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y());
drawPolygons(&painter, polygons);
drawLines(&painter, lines);
drawTextItems(&painter, textItems);
qDeleteAll(textItems);
_valid = true;
//painter.setPen(Qt::red);
//painter.setRenderHint(QPainter::Antialiasing, false);
//painter.drawRect(QRect(_xy, _pixmap.size()));
}

View File

@ -17,14 +17,11 @@ class Style;
class RasterTile class RasterTile
{ {
public: public:
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform, MapData *data,
const Style *style, int zoom, const QRect &rect, qreal ratio, int zoom, const QRect &rect, qreal ratio, const QString &key)
const QString &key, const QList<MapData::Poly> &polygons, : _proj(proj), _transform(transform), _data(data), _zoom(zoom),
const QList<MapData::Poly> &lines, QList<MapData::Point> &points) _rect(rect), _ratio(ratio), _key(key),
: _proj(proj), _transform(transform), _style(style), _zoom(zoom), _pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
_rect(rect), _ratio(ratio), _key(key),
_pixmap(rect.width() * ratio, rect.height() * ratio), _polygons(polygons),
_lines(lines), _points(points), _valid(false) {}
const QString &key() const {return _key;} const QString &key() const {return _key;}
QPoint xy() const {return _rect.topLeft();} QPoint xy() const {return _rect.topLeft();}
@ -34,32 +31,36 @@ public:
void render(); void render();
private: private:
void fetchData(QList<MapData::Poly> &polygons, QList<MapData::Poly> &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));}
void ll2xy(QList<MapData::Poly> &polys); void ll2xy(QList<MapData::Poly> &polys);
void ll2xy(QList<MapData::Point> &points); void ll2xy(QList<MapData::Point> &points);
void drawPolygons(QPainter *painter); void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons);
void drawLines(QPainter *painter); void drawLines(QPainter *painter, const QList<MapData::Poly> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems); void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void processPolygons(QList<TextItem *> &textItems); void processPolygons(const QList<MapData::Poly> &polygons,
void processLines(QList<TextItem*> &textItems); QList<TextItem *> &textItems);
void processPoints(QList<TextItem*> &textItems); void processLines(QList<MapData::Poly> &lines,
void processShields(QList<TextItem*> &textItems); QList<TextItem*> &textItems);
void processStreetNames(QList<TextItem*> &textItems); void processPoints(QList<MapData::Point> &points,
QList<TextItem*> &textItems);
void processShields(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems);
void processStreetNames(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems);
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
const Style *_style; MapData *_data;
int _zoom; int _zoom;
QRect _rect; QRect _rect;
qreal _ratio; qreal _ratio;
QString _key; QString _key;
QPixmap _pixmap; QPixmap _pixmap;
QList<MapData::Poly> _polygons;
QList<MapData::Poly> _lines;
QList<MapData::Point> _points;
bool _valid; bool _valid;
}; };

View File

@ -1,5 +1,6 @@
#include "common/rectc.h" #include "common/rectc.h"
#include "common/garmin.h" #include "common/garmin.h"
#include "common/hash.h"
#include "deltastream.h" #include "deltastream.h"
#include "huffmanstream.h" #include "huffmanstream.h"
#include "style.h" #include "style.h"
@ -13,12 +14,10 @@ using namespace IMG;
#define MASK(bits) ((1U << (bits)) - 1U) #define MASK(bits) ((1U << (bits)) - 1U)
static quint64 pointId(const QPoint &pos, quint32 type) static quint64 pointId(const QPoint &pos, quint32 type, const QString &label)
{ {
quint64 id; quint64 hash = qHash(pos) ^ qHash(label);
quint64 id = ((quint64)type)<<40 | (hash & 0xFFFFFFFFFF);
uint hash = (uint)qHash(QPair<int, int>(pos.x(), pos.y()));
id = ((quint64)type)<<32 | hash;
// Increase rendering priorities for some special items // Increase rendering priorities for some special items
if (!Style::isCountry(type) && !Style::isMarina(type)) if (!Style::isCountry(type) && !Style::isMarina(type))
@ -484,11 +483,11 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
point.type = (quint16)type<<8 | subtype; point.type = (quint16)type<<8 | subtype;
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y())); point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
point.id = pointId(pos, point.type);
if (lbl && (labelPtr & 0x3FFFFF)) if (lbl && (labelPtr & 0x3FFFFF))
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF,
labelPtr & 0x400000, !(Style::isCountry(point.type) labelPtr & 0x400000, !(Style::isCountry(point.type)
|| Style::isState(point.type)), Style::isSpot(point.type)); || Style::isState(point.type)), Style::isSpot(point.type));
point.id = pointId(pos, point.type, point.label.text());
points->append(point); points->append(point);
} }
@ -537,9 +536,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv,
continue; continue;
point.coordinates = Coordinates(toWGS24(p.x()), toWGS24(p.y())); point.coordinates = Coordinates(toWGS24(p.x()), toWGS24(p.y()));
point.id = pointId(p, point.type);
if (lbl && (labelPtr & 0x3FFFFF)) if (lbl && (labelPtr & 0x3FFFFF))
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF); point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
point.id = pointId(p, point.type, point.label.text());
points->append(point); points->append(point);
} }

View File

@ -102,13 +102,18 @@ void VectorTile::clear()
void VectorTile::polys(const RectC &rect, const Zoom &zoom, void VectorTile::polys(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, MapData::Polys> *polyCache) MapData::PolyCache *polyCache, QMutex *lock)
{ {
SubFile::Handle *rgnHdl = 0, *lblHdl = 0, *netHdl = 0, *nodHdl = 0, SubFile::Handle *rgnHdl = 0, *lblHdl = 0, *netHdl = 0, *nodHdl = 0,
*nodHdl2 = 0; *nodHdl2 = 0;
if (_loaded < 0) lock->lock();
if (_loaded < 0) {
lock->unlock();
return; return;
}
if (!_loaded) { if (!_loaded) {
rgnHdl = new SubFile::Handle(_rgn); rgnHdl = new SubFile::Handle(_rgn);
lblHdl = new SubFile::Handle(_lbl); lblHdl = new SubFile::Handle(_lbl);
@ -116,6 +121,7 @@ void VectorTile::polys(const RectC &rect, const Zoom &zoom,
nodHdl = new SubFile::Handle(_nod); nodHdl = new SubFile::Handle(_nod);
if (!load(*rgnHdl, *lblHdl, *netHdl, *nodHdl)) { if (!load(*rgnHdl, *lblHdl, *netHdl, *nodHdl)) {
lock->unlock();
delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl; delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl;
return; return;
} }
@ -166,17 +172,24 @@ void VectorTile::polys(const RectC &rect, const Zoom &zoom,
} }
} }
lock->unlock();
delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl; delete nodHdl2; delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl; delete nodHdl2;
} }
void VectorTile::points(const RectC &rect, const Zoom &zoom, void VectorTile::points(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QCache<const SubDiv *, QList<MapData::Point> *points, QCache<const SubDiv *,
QList<MapData::Point> > *pointCache) QList<MapData::Point> > *pointCache, QMutex *lock)
{ {
SubFile::Handle *rgnHdl = 0, *lblHdl = 0; SubFile::Handle *rgnHdl = 0, *lblHdl = 0;
if (_loaded < 0) lock->lock();
if (_loaded < 0) {
lock->unlock();
return; return;
}
if (!_loaded) { if (!_loaded) {
rgnHdl = new SubFile::Handle(_rgn); rgnHdl = new SubFile::Handle(_rgn);
lblHdl = new SubFile::Handle(_lbl); lblHdl = new SubFile::Handle(_lbl);
@ -184,6 +197,7 @@ void VectorTile::points(const RectC &rect, const Zoom &zoom,
SubFile::Handle netHdl(_net); SubFile::Handle netHdl(_net);
if (!load(*rgnHdl, *lblHdl, netHdl, nodHdl)) { if (!load(*rgnHdl, *lblHdl, netHdl, nodHdl)) {
lock->unlock();
delete rgnHdl; delete lblHdl; delete rgnHdl; delete lblHdl;
return; return;
} }
@ -217,6 +231,8 @@ void VectorTile::points(const RectC &rect, const Zoom &zoom,
copyPoints(rect, pl, points); copyPoints(rect, pl, points);
} }
lock->unlock();
delete rgnHdl; delete lblHdl; delete rgnHdl; delete lblHdl;
} }

View File

@ -29,10 +29,10 @@ public:
void polys(const RectC &rect, const Zoom &zoom, void polys(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, MapData::Polys> *polyCache); MapData::PolyCache *polyCache, QMutex *lock);
void points(const RectC &rect, const Zoom &zoom, void points(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QCache<const SubDiv*, QList<MapData::Point> *points, QCache<const SubDiv*,
QList<MapData::Point> > *pointCache); QList<MapData::Point> > *pointCache, QMutex *lock);
static bool isTileFile(SubFile::Type type) static bool isTileFile(SubFile::Type type)
{ {

View File

@ -6,11 +6,10 @@
#include "pcs.h" #include "pcs.h"
#include "encmap.h" #include "encmap.h"
#define TILE_SIZE 512
#define TEXT_EXTENT 160
using namespace ENC; using namespace ENC;
#define TILE_SIZE 512
ENCMap::ENCMap(const QString &fileName, QObject *parent) ENCMap::ENCMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _data(fileName), _projection(PCS::pcs(3857)), : Map(fileName, parent), _data(fileName), _projection(PCS::pcs(3857)),
@ -180,32 +179,9 @@ void ENCMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
QPixmap pm; QPixmap pm;
if (QPixmapCache::find(key(_zoom, ttl), &pm)) if (QPixmapCache::find(key(_zoom, ttl), &pm))
painter->drawPixmap(ttl, pm); painter->drawPixmap(ttl, pm);
else { else
QList<MapData::Poly*> polygons; tiles.append(RasterTile(_projection, _transform, &_data,
QList<MapData::Line*> lines; _zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio));
QList<MapData::Point*> points;
QRectF polyRect(ttl, QPointF(ttl.x() + TILE_SIZE,
ttl.y() + TILE_SIZE));
polyRect &= _bounds;
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
RectC polyRectC(polyRectD.toRectC(_projection, 20));
_data.lines(polyRectC, &lines);
_data.polygons(polyRectC, &polygons);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT), QPointF(ttl.x() + TILE_SIZE
+ TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT));
pointRect &= _bounds;
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.points(pointRectD.toRectC(_projection, 20), &points);
tiles.append(RasterTile(_projection, _transform, _data.zooms(),
_zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio,
lines, polygons, points));
}
} }
} }

View File

@ -16,7 +16,6 @@
using namespace IMG; using namespace IMG;
#define TILE_SIZE 384 #define TILE_SIZE 384
#define TEXT_EXTENT 160
static RectC limitBounds(const RectC &bounds, const Projection &proj) static RectC limitBounds(const RectC &bounds, const Projection &proj)
{ {
@ -241,30 +240,9 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
if (QPixmapCache::find(key, &pm)) if (QPixmapCache::find(key, &pm))
painter->drawPixmap(ttl, pm); painter->drawPixmap(ttl, pm);
else { else {
QList<MapData::Poly> polygons, lines; tiles.append(RasterTile(_projection, _transform, _data.at(n),
QList<MapData::Point> points; _zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio,
key));
QRectF polyRect(ttl, QPointF(ttl.x() + TILE_SIZE,
ttl.y() + TILE_SIZE));
polyRect &= _bounds;
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
_data.at(n)->polys(polyRectD.toRectC(_projection, 20), _zoom,
&polygons, &lines);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT), QPointF(ttl.x() + TILE_SIZE
+ TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT));
pointRect &= _bounds;
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.at(n)->points(pointRectD.toRectC(_projection, 20),
_zoom, &points);
tiles.append(RasterTile(_projection, _transform,
_data.at(n)->style(), _zoom,
QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio, key,
polygons, lines, points));
} }
} }
} }

View File

@ -5,34 +5,26 @@
#define SAMPLES 100 #define SAMPLES 100
void Map::growLeft(const QPointF &p, RectC &rect) static void growLeft(const Coordinates &c, RectC &rect)
{ {
Coordinates c(xy2ll(p));
if (c.lon() < rect.left()) if (c.lon() < rect.left())
rect.setLeft(c.lon()); rect.setLeft(c.lon());
} }
void Map::growRight(const QPointF &p, RectC &rect) static void growRight(const Coordinates &c, RectC &rect)
{ {
Coordinates c(xy2ll(p));
if (c.lon() > rect.right()) if (c.lon() > rect.right())
rect.setRight(c.lon()); rect.setRight(c.lon());
} }
void Map::growTop(const QPointF &p, RectC &rect) static void growTop(const Coordinates &c, RectC &rect)
{ {
Coordinates c(xy2ll(p));
if (c.lat() > rect.top()) if (c.lat() > rect.top())
rect.setTop(c.lat()); rect.setTop(c.lat());
} }
void Map::growBottom(const QPointF &p, RectC &rect) static void growBottom(const Coordinates &c, RectC &rect)
{ {
Coordinates c(xy2ll(p));
if (c.lat() < rect.bottom()) if (c.lat() < rect.bottom())
rect.setBottom(c.lat()); rect.setBottom(c.lat());
} }
@ -53,14 +45,14 @@ RectC Map::llBounds(const Projection &proj)
for (int i = 0; i <= SAMPLES; i++) { for (int i = 0; i <= SAMPLES; i++) {
double x = b.left() + i * dx; double x = b.left() + i * dx;
growBottom(QPointF(x, b.bottom()), rect); growBottom(xy2ll(QPointF(x, b.bottom())), rect);
growTop(QPointF(x, b.top()), rect); growTop(xy2ll(QPointF(x, b.top())), rect);
} }
for (int i = 0; i <= SAMPLES; i++) { for (int i = 0; i <= SAMPLES; i++) {
double y = b.top() + i * dy; double y = b.top() + i * dy;
growLeft(QPointF(b.left(), y), rect); growLeft(xy2ll(QPointF(b.left(), y)), rect);
growRight(QPointF(b.right(), y), rect); growRight(xy2ll(QPointF(b.right(), y)), rect);
} }
return rect; return rect;

View File

@ -62,11 +62,6 @@ signals:
void mapLoaded(); void mapLoaded();
private: private:
void growLeft(const QPointF &p, RectC &rect);
void growRight(const QPointF &p, RectC &rect);
void growTop(const QPointF &p, RectC &rect);
void growBottom(const QPointF &p, RectC &rect);
QString _path; QString _path;
}; };

View File

@ -208,13 +208,15 @@ bool MapData::readTags(SubFile &subfile, int count,
bool MapData::readSubFiles() bool MapData::readSubFiles()
{ {
QDataStream stream(&_file); /* both _pointFile and _pathFile can be used here */
QDataStream stream(&_pointFile);
for (int i = 0; i < _subFiles.size(); i++) { for (int i = 0; i < _subFiles.size(); i++) {
const SubFileInfo &f = _subFiles.at(i); const SubFileInfo &f = _subFiles.at(i);
quint64 offset, nextOffset; quint64 offset, nextOffset;
stream.device()->seek(f.offset); if (!stream.device()->seek(f.offset))
return false;
QPoint tl(OSM::ll2tile(_bounds.topLeft(), f.base)); QPoint tl(OSM::ll2tile(_bounds.topLeft(), f.base));
QPoint br(OSM::ll2tile(_bounds.bottomRight(), f.base)); QPoint br(OSM::ll2tile(_bounds.bottomRight(), f.base));
@ -359,7 +361,7 @@ bool MapData::readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap)
return true; return true;
} }
bool MapData::readHeader() bool MapData::readHeader(QFile &file)
{ {
char magic[MAGIC_SIZE]; char magic[MAGIC_SIZE];
quint32 hdrSize; quint32 hdrSize;
@ -367,18 +369,18 @@ bool MapData::readHeader()
bool debugMap; bool debugMap;
if (_file.read(magic, MAGIC_SIZE) < (qint64)MAGIC_SIZE if (file.read(magic, MAGIC_SIZE) < (qint64)MAGIC_SIZE
|| memcmp(magic, MAGIC, MAGIC_SIZE)) { || memcmp(magic, MAGIC, MAGIC_SIZE)) {
_errorString = "Not a Mapsforge map"; _errorString = "Not a Mapsforge map";
return false; return false;
} }
if (_file.read((char*)&hdrSize, sizeof(hdrSize)) < (qint64)sizeof(hdrSize)) { if (file.read((char*)&hdrSize, sizeof(hdrSize)) < (qint64)sizeof(hdrSize)) {
_errorString = "Unexpected EOF"; _errorString = "Unexpected EOF";
return false; return false;
} }
SubFile hdr(_file, MAGIC_SIZE, qFromBigEndian(hdrSize)); SubFile hdr(file, MAGIC_SIZE, qFromBigEndian(hdrSize));
if (!readMapInfo(hdr, projection, debugMap)) { if (!readMapInfo(hdr, projection, debugMap)) {
_errorString = "Error reading map info"; _errorString = "Error reading map info";
@ -407,18 +409,19 @@ bool MapData::readHeader()
return true; return true;
} }
MapData::MapData(const QString &fileName) : _file(fileName), _valid(false) MapData::MapData(const QString &fileName)
: _pointFile(fileName), _pathFile(fileName), _valid(false)
{ {
if (!_file.open(QFile::ReadOnly | QIODevice::Unbuffered)) { QFile file(fileName);
_errorString = _file.errorString();
if (!file.open(QFile::ReadOnly | QIODevice::Unbuffered)) {
_errorString = file.errorString();
return; return;
} }
if (!readHeader()) if (!readHeader(file))
return; return;
_file.close();
_pathCache.setMaxCost(256); _pathCache.setMaxCost(256);
_pointCache.setMaxCost(256); _pointCache.setMaxCost(256);
@ -444,13 +447,16 @@ RectC MapData::bounds() const
void MapData::load() void MapData::load()
{ {
if (_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) _pointFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
readSubFiles(); _pathFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
readSubFiles();
} }
void MapData::clear() void MapData::clear()
{ {
_file.close(); _pointFile.close();
_pathFile.close();
_pathCache.clear(); _pathCache.clear();
_pointCache.clear(); _pointCache.clear();
@ -497,6 +503,9 @@ int MapData::level(int zoom) const
void MapData::points(const RectC &rect, int zoom, QList<Point> *list) void MapData::points(const RectC &rect, int zoom, QList<Point> *list)
{ {
if (!rect.isValid())
return;
int l(level(zoom)); int l(level(zoom));
PointCTX ctx(this, rect, zoom, list); PointCTX ctx(this, rect, zoom, list);
double min[2], max[2]; double min[2], max[2];
@ -513,6 +522,9 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
QList<Point> *list) QList<Point> *list)
{ {
Key key(tile, zoom); Key key(tile, zoom);
_pointLock.lock();
QList<Point> *cached = _pointCache.object(key); QList<Point> *cached = _pointCache.object(key);
if (!cached) { if (!cached) {
@ -524,10 +536,15 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
delete p; delete p;
} else } else
copyPoints(rect, cached, list); copyPoints(rect, cached, list);
_pointLock.unlock();
} }
void MapData::paths(const RectC &rect, int zoom, QList<Path> *list) void MapData::paths(const RectC &rect, int zoom, QList<Path> *list)
{ {
if (!rect.isValid())
return;
int l(level(zoom)); int l(level(zoom));
PathCTX ctx(this, rect, zoom, list); PathCTX ctx(this, rect, zoom, list);
double min[2], max[2]; double min[2], max[2];
@ -544,6 +561,9 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
QList<Path> *list) QList<Path> *list)
{ {
Key key(tile, zoom); Key key(tile, zoom);
_pathLock.lock();
QList<Path> *cached = _pathCache.object(key); QList<Path> *cached = _pathCache.object(key);
if (!cached) { if (!cached) {
@ -555,12 +575,14 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
delete p; delete p;
} else } else
copyPaths(rect, cached, list); copyPaths(rect, cached, list);
_pathLock.unlock();
} }
bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list) bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
{ {
const SubFileInfo &info = _subFiles.at(level(zoom)); const SubFileInfo &info = _subFiles.at(level(zoom));
SubFile subfile(_file, info.offset, info.size); SubFile subfile(_pathFile, info.offset, info.size);
int rows = info.max - info.min + 1; int rows = info.max - info.min + 1;
QVector<unsigned> paths(rows); QVector<unsigned> paths(rows);
quint32 blocks, unused, val, cnt = 0; quint32 blocks, unused, val, cnt = 0;
@ -584,8 +606,10 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
if (!subfile.seek(subfile.pos() + val)) if (!subfile.seek(subfile.pos() + val))
return false; return false;
paths.reserve(paths[zoom - info.min]);
for (unsigned i = 0; i < paths[zoom - info.min]; i++) { for (unsigned i = 0; i < paths[zoom - info.min]; i++) {
Path p(subfile.offset() + subfile.pos()); Path p;
qint32 lon = 0, lat = 0; qint32 lon = 0, lat = 0;
if (!(subfile.readVUInt32(unused) && subfile.readUInt16(bitmap) if (!(subfile.readVUInt32(unused) && subfile.readUInt16(bitmap)
@ -644,7 +668,7 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list) bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
{ {
const SubFileInfo &info = _subFiles.at(level(zoom)); const SubFileInfo &info = _subFiles.at(level(zoom));
SubFile subfile(_file, info.offset, info.size); SubFile subfile(_pointFile, info.offset, info.size);
int rows = info.max - info.min + 1; int rows = info.max - info.min + 1;
QVector<unsigned> points(rows); QVector<unsigned> points(rows);
quint32 val, unused, cnt = 0; quint32 val, unused, cnt = 0;
@ -665,6 +689,8 @@ bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
if (!subfile.readVUInt32(unused)) if (!subfile.readVUInt32(unused))
return false; return false;
list->reserve(points[zoom - info.min]);
for (unsigned i = 0; i < points[zoom - info.min]; i++) { for (unsigned i = 0; i < points[zoom - info.min]; i++) {
qint32 lat, lon; qint32 lat, lon;

View File

@ -3,6 +3,7 @@
#include <QFile> #include <QFile>
#include <QCache> #include <QCache>
#include <QMutex>
#include "common/hash.h" #include "common/hash.h"
#include "common/rectc.h" #include "common/rectc.h"
#include "common/rtree.h" #include "common/rtree.h"
@ -36,10 +37,7 @@ public:
}; };
struct Point { struct Point {
Point(const Coordinates &c) : coordinates(c) Point(const Coordinates &c) : id(qHash(c)), coordinates(c) {}
{
id = (quint64)qHash(QPair<double, double>(c.lon(), c.lat()));
}
quint64 id; quint64 id;
Coordinates coordinates; Coordinates coordinates;
@ -48,9 +46,6 @@ public:
}; };
struct Path { struct Path {
Path(quint64 id) : id(id) {}
quint64 id;
Polygon poly; Polygon poly;
QVector<Tag> tags; QVector<Tag> tags;
Coordinates labelPos; Coordinates labelPos;
@ -59,8 +54,6 @@ public:
bool operator<(const Path &other) const bool operator<(const Path &other) const
{return layer < other.layer;} {return layer < other.layer;}
bool operator==(const Path &other) const
{return (id == other.id);}
}; };
RectC bounds() const; RectC bounds() const;
@ -146,7 +139,7 @@ private:
bool readTagInfo(SubFile &hdr); bool readTagInfo(SubFile &hdr);
bool readTagInfo(SubFile &hdr, QVector<TagSource> &tags); bool readTagInfo(SubFile &hdr, QVector<TagSource> &tags);
bool readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap); bool readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap);
bool readHeader(); bool readHeader(QFile &file);
bool readSubFiles(); bool readSubFiles();
void clearTiles(); void clearTiles();
@ -165,7 +158,7 @@ private:
friend HASH_T qHash(const MapData::Key &key); friend HASH_T qHash(const MapData::Key &key);
QFile _file; QFile _pointFile, _pathFile;
RectC _bounds; RectC _bounds;
quint16 _tileSize; quint16 _tileSize;
QVector<SubFileInfo> _subFiles; QVector<SubFileInfo> _subFiles;
@ -175,6 +168,7 @@ private:
QCache<Key, QList<Path> > _pathCache; QCache<Key, QList<Path> > _pathCache;
QCache<Key, QList<Point> > _pointCache; QCache<Key, QList<Point> > _pointCache;
QMutex _pathLock, _pointLock;
bool _valid; bool _valid;
QString _errorString; QString _errorString;
@ -190,11 +184,6 @@ inline HASH_T qHash(const MapData::Tag &tag)
return ::qHash(tag.key) ^ ::qHash(tag.value); return ::qHash(tag.key) ^ ::qHash(tag.value);
} }
inline HASH_T qHash(const MapData::Path &path)
{
return ::qHash(path.id);
}
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -1,10 +1,13 @@
#include <QPainter> #include <QPainter>
#include <QCache> #include <QCache>
#include "common/programpaths.h" #include "common/programpaths.h"
#include "map/rectd.h"
#include "rastertile.h" #include "rastertile.h"
using namespace Mapsforge; using namespace Mapsforge;
#define TEXT_EXTENT 160
static qreal area(const QPainterPath &polygon) static qreal area(const QPainterPath &polygon)
{ {
qreal area = 0; qreal area = 0;
@ -52,14 +55,15 @@ static const QColor *haloColor(const Style::TextRender *ti)
? &ti->strokeColor() : 0; ? &ti->strokeColor() : 0;
} }
void RasterTile::processPointLabels(QList<TextItem*> &textItems) void RasterTile::processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems)
{ {
QList<const Style::TextRender*> labels(_style->pointLabels(_zoom)); QList<const Style::TextRender*> labels(_style->pointLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->pointSymbols(_zoom)); QList<const Style::Symbol*> symbols(_style->pointSymbols(_zoom));
QList<PainterPoint> points; QList<PainterPoint> painterPoints;
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = _points.at(i); const MapData::Point &point = points.at(i);
const QByteArray *lbl = 0; const QByteArray *lbl = 0;
const Style::TextRender *ti = 0; const Style::TextRender *ti = 0;
const Style::Symbol *si = 0; const Style::Symbol *si = 0;
@ -83,13 +87,13 @@ void RasterTile::processPointLabels(QList<TextItem*> &textItems)
} }
if (ti || si) if (ti || si)
points.append(PainterPoint(&point, lbl, si, ti)); painterPoints.append(PainterPoint(&point, lbl, si, ti));
} }
std::sort(points.begin(), points.end()); std::sort(painterPoints.begin(), painterPoints.end());
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < painterPoints.size(); i++) {
const PainterPoint &p = points.at(i); const PainterPoint &p = painterPoints.at(i);
const QImage *img = p.si ? &p.si->img() : 0; const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0; const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0; const QColor *color = p.ti ? &p.ti->fillColor() : 0;
@ -200,17 +204,17 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
{ {
QPainterPath path; QPainterPath path;
if (curve) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
int size = 0; int size = 0;
for (int i = 0; i < polygon.size(); i++) for (int i = 0; i < polygon.size(); i++)
size += polygon.at(i).size(); size += polygon.at(i).size();
path.reserve(size); path.reserve(size);
#endif // QT 5.13 #endif // QT 5.13
for (int i = 0; i < polygon.size(); i++) { for (int i = 0; i < polygon.size(); i++) {
const QVector<Coordinates> &subpath = polygon.at(i); const QVector<Coordinates> &subpath = polygon.at(i);
if (curve) {
QPointF p1(ll2xy(subpath.first())); QPointF p1(ll2xy(subpath.first()));
QPointF p2(0, 0); QPointF p2(0, 0);
QPointF p3(0, 0); QPointF p3(0, 0);
@ -223,25 +227,31 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
p1 = p3; p1 = p3;
} }
path.quadTo(p2, p3); path.quadTo(p2, p3);
} else { }
path.moveTo(ll2xy(subpath.first())); } else {
for (int j = 1; j < subpath.size(); j++) for (int i = 0; i < polygon.size(); i++) {
path.lineTo(ll2xy(subpath.at(j))); const QVector<Coordinates> &subpath = polygon.at(i);
QVector<QPointF> p(subpath.size());
for (int j = 0; j < subpath.size(); j++)
p[j] = ll2xy(subpath.at(j));
path.addPolygon(p);
} }
} }
return path; return path;
} }
void RasterTile::pathInstructions(QVector<PainterPath> &paths, void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions) QVector<RasterTile::RenderInstruction> &instructions)
{ {
QCache<PathKey, QList<const Style::PathRender *> > cache(8192); QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
QList<const Style::PathRender*> *ri; QList<const Style::PathRender*> *ri;
for (int i = 0; i < _paths.size(); i++) { for (int i = 0; i < paths.size(); i++) {
const MapData::Path &path = _paths.at(i); const MapData::Path &path = paths.at(i);
PainterPath &rp = paths[i]; PainterPath &rp = painterPaths[i];
PathKey key(_zoom, path.closed, path.tags); PathKey key(_zoom, path.closed, path.tags);
rp.path = &path; rp.path = &path;
@ -259,14 +269,14 @@ void RasterTile::pathInstructions(QVector<PainterPath> &paths,
} }
} }
void RasterTile::circleInstructions( void RasterTile::circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions) QVector<RasterTile::RenderInstruction> &instructions)
{ {
QCache<PointKey, QList<const Style::CircleRender *> > cache(8192); QCache<PointKey, QList<const Style::CircleRender *> > cache(8192);
QList<const Style::CircleRender*> *ri; QList<const Style::CircleRender*> *ri;
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = _points.at(i); const MapData::Point &point = points.at(i);
PointKey key(_zoom, point.tags); PointKey key(_zoom, point.tags);
if (!(ri = cache.object(key))) { if (!(ri = cache.object(key))) {
@ -282,11 +292,12 @@ void RasterTile::circleInstructions(
} }
} }
void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths) void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
const QList<MapData::Point> &points, QVector<PainterPath> &painterPaths)
{ {
QVector<RenderInstruction> instructions; QVector<RenderInstruction> instructions;
pathInstructions(paths, instructions); pathInstructions(paths, painterPaths, instructions);
circleInstructions(instructions); circleInstructions(points, instructions);
std::sort(instructions.begin(), instructions.end()); std::sort(instructions.begin(), instructions.end());
for (int i = 0; i < instructions.size(); i++) { for (int i = 0; i < instructions.size(); i++) {
@ -313,10 +324,37 @@ void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
} }
} }
void RasterTile::fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points)
{
QPoint ttl(_rect.topLeft());
/* Add a "sub-pixel" margin to assure the tile areas do not
overlap on the border lines. This prevents areas overlap
artifacts at least when using the EPSG:3857 projection. */
QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5),
QPointF(ttl.x() + _rect.width() - 0.5, ttl.y() + _rect.height() - 0.5));
RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight()));
_data->paths(pathRectD.toRectC(_proj, 20), _zoom, &paths);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()
+ TEXT_EXTENT));
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data->points(pointRectD.toRectC(_proj, 20), _zoom, &points);
}
void RasterTile::render() void RasterTile::render()
{ {
QList<MapData::Path> paths;
QList<MapData::Point> points;
fetchData(paths, points);
QList<TextItem*> textItems; QList<TextItem*> textItems;
QVector<PainterPath> renderPaths(_paths.size()); QVector<PainterPath> renderPaths(paths.size());
_pixmap.setDevicePixelRatio(_ratio); _pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent); _pixmap.fill(Qt::transparent);
@ -325,9 +363,9 @@ void RasterTile::render()
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y()); painter.translate(-_rect.x(), -_rect.y());
drawPaths(&painter, renderPaths); drawPaths(&painter, paths, points, renderPaths);
processPointLabels(textItems); processPointLabels(points, textItems);
processAreaLabels(textItems, renderPaths); processAreaLabels(textItems, renderPaths);
processLineLabels(textItems, renderPaths); processLineLabels(textItems, renderPaths);
drawTextItems(&painter, textItems); drawTextItems(&painter, textItems);

View File

@ -15,11 +15,10 @@ class RasterTile
{ {
public: public:
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Style *style, int zoom, const QRect &rect, qreal ratio, const Style *style, MapData *data, int zoom, const QRect &rect,
const QList<MapData::Path> &paths, const QList<MapData::Point> &points) qreal ratio) : _proj(proj), _transform(transform), _style(style),
: _proj(proj), _transform(transform), _style(style), _data(data), _zoom(zoom), _rect(rect), _ratio(ratio),
_zoom(zoom), _rect(rect), _ratio(ratio), _pixmap(rect.width() * ratio, _pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
rect.height() * ratio), _paths(paths), _points(points), _valid(false) {}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
QPoint xy() const {return _rect.topLeft();} QPoint xy() const {return _rect.topLeft();}
@ -147,31 +146,33 @@ private:
friend HASH_T qHash(const RasterTile::PathKey &key); friend HASH_T qHash(const RasterTile::PathKey &key);
friend HASH_T qHash(const RasterTile::PointKey &key); friend HASH_T qHash(const RasterTile::PointKey &key);
void pathInstructions(QVector<PainterPath> &paths, void fetchData(QList<MapData::Path> &paths, QList<MapData::Point> &points);
void pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions);
void circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions); QVector<RasterTile::RenderInstruction> &instructions);
void circleInstructions(QVector<RasterTile::RenderInstruction> &instructions);
QPointF ll2xy(const Coordinates &c) const QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));} {return _transform.proj2img(_proj.ll2xy(c));}
void processPointLabels(QList<TextItem*> &textItems); void processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems);
void processAreaLabels(QList<TextItem*> &textItems, void processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths); QVector<PainterPath> &paths);
void processLineLabels(QList<TextItem*> &textItems, void processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths); QVector<PainterPath> &paths);
QPainterPath painterPath(const Polygon &polygon, bool curve) const; QPainterPath painterPath(const Polygon &polygon, bool curve) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems); void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void drawPaths(QPainter *painter, QVector<PainterPath> &paths); void drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
const QList<MapData::Point> &points, QVector<PainterPath> &painterPaths);
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
const Style *_style; const Style *_style;
MapData *_data;
int _zoom; int _zoom;
QRect _rect; QRect _rect;
qreal _ratio; qreal _ratio;
QPixmap _pixmap; QPixmap _pixmap;
QList<MapData::Path> _paths;
QList<MapData::Point> _points;
bool _valid; bool _valid;
}; };

View File

@ -154,6 +154,13 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return; return;
} }
} }
if (attr.hasAttribute("scale")) {
QString scale(attr.value("scale").toString());
if (scale == "all")
ri._scale = PathRender::Scale::All;
else if (scale == "none")
ri._scale = PathRender::Scale::None;
}
if (attr.hasAttribute("src")) if (attr.hasAttribute("src"))
file = resourcePath(attr.value("src").toString(), dir); file = resourcePath(attr.value("src").toString(), dir);
if (attr.hasAttribute("symbol-height")) { if (attr.hasAttribute("symbol-height")) {
@ -226,6 +233,13 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
else if (join == "bevel") else if (join == "bevel")
ri._strokeJoin = Qt::BevelJoin; ri._strokeJoin = Qt::BevelJoin;
} }
if (attr.hasAttribute("scale")) {
QString scale(attr.value("scale").toString());
if (scale == "all")
ri._scale = PathRender::Scale::All;
else if (scale == "none")
ri._scale = PathRender::Scale::None;
}
if (attr.hasAttribute("curve")) { if (attr.hasAttribute("curve")) {
QString curve(attr.value("curve").toString()); QString curve(attr.value("curve").toString());
if (curve == "cubic") if (curve == "cubic")
@ -656,14 +670,18 @@ QList<const Style::Symbol*> Style::areaSymbols(int zoom) const
QPen Style::PathRender::pen(int zoom) const QPen Style::PathRender::pen(int zoom) const
{ {
if (_strokeColor.isValid()) { if (_strokeColor.isValid()) {
qreal width = (zoom >= 12) qreal width = (_scale > None && zoom >= 12)
? pow(1.5, zoom - 12) * _strokeWidth : _strokeWidth; ? pow(1.5, zoom - 12) * _strokeWidth : _strokeWidth;
QPen p(QBrush(_strokeColor), width, Qt::SolidLine, _strokeCap, QPen p(QBrush(_strokeColor), width, Qt::SolidLine, _strokeCap,
_strokeJoin); _strokeJoin);
if (!_strokeDasharray.isEmpty()) { if (!_strokeDasharray.isEmpty()) {
QVector<qreal>pattern(_strokeDasharray); QVector<qreal>pattern(_strokeDasharray);
for (int i = 0; i < _strokeDasharray.size(); i++) for (int i = 0; i < _strokeDasharray.size(); i++) {
if (_scale > Stroke && zoom >= 12)
pattern[i] = (pow(1.5, zoom - 12) * pattern[i]);
// QPainter pattern is specified in units of the pens width!
pattern[i] /= width; pattern[i] /= width;
}
p.setDashPattern(pattern); p.setDashPattern(pattern);
} }
return p; return p;

View File

@ -136,7 +136,8 @@ public:
public: public:
PathRender(const Rule &rule, int zOrder) : Render(rule), PathRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap), _zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap),
_strokeJoin(Qt::RoundJoin), _area(false), _curve(false) {} _strokeJoin(Qt::RoundJoin), _area(false), _curve(false),
_scale(Stroke) {}
int zOrder() const {return _zOrder;} int zOrder() const {return _zOrder;}
QPen pen(int zoom) const; QPen pen(int zoom) const;
@ -147,6 +148,8 @@ public:
private: private:
friend class Style; friend class Style;
enum Scale {None, Stroke, All};
int _zOrder; int _zOrder;
QColor _strokeColor; QColor _strokeColor;
qreal _strokeWidth; qreal _strokeWidth;
@ -155,6 +158,7 @@ public:
Qt::PenJoinStyle _strokeJoin; Qt::PenJoinStyle _strokeJoin;
QBrush _brush; QBrush _brush;
bool _area, _curve; bool _area, _curve;
Scale _scale;
}; };
class CircleRender : public Render class CircleRender : public Render

View File

@ -14,7 +14,6 @@ public:
: _file(file), _offset(offset), _size(size), _pos(-1), : _file(file), _offset(offset), _size(size), _pos(-1),
_blockNum(-1), _blockPos(-1) {} _blockNum(-1), _blockPos(-1) {}
quint64 offset() const {return _offset;}
quint64 pos() const {return _pos;} quint64 pos() const {return _pos;}
bool seek(quint64 pos); bool seek(quint64 pos);

View File

@ -2,15 +2,13 @@
#include <QPixmapCache> #include <QPixmapCache>
#include "common/wgs84.h" #include "common/wgs84.h"
#include "common/util.h" #include "common/util.h"
#include "pcs.h"
#include "rectd.h" #include "rectd.h"
#include "pcs.h"
#include "mapsforgemap.h" #include "mapsforgemap.h"
using namespace Mapsforge; using namespace Mapsforge;
#define TEXT_EXTENT 160
MapsforgeMap::MapsforgeMap(const QString &fileName, QObject *parent) MapsforgeMap::MapsforgeMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _data(fileName), _zoom(0), : Map(fileName, parent), _data(fileName), _zoom(0),
_projection(PCS::pcs(3857)), _tileRatio(1.0) _projection(PCS::pcs(3857)), _tileRatio(1.0)
@ -188,32 +186,9 @@ void MapsforgeMap::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 {
QList<MapData::Path> paths; tiles.append(RasterTile(_projection, _transform, &_style, &_data,
QList<MapData::Point> points; _zoom, QRect(ttl, QSize(_data.tileSize(), _data.tileSize())),
_tileRatio));
/* Add a "sub-pixel" margin to assure the tile areas do not
overlap on the border lines. This prevents areas overlap
artifacts at least when using the EPSG:3857 projection. */
QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5),
QPointF(ttl.x() + _data.tileSize() - 0.5, ttl.y()
+ _data.tileSize() - 0.5));
pathRect &= _bounds;
RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight()));
_data.paths(pathRectD.toRectC(_projection, 20), _zoom, &paths);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y()
- TEXT_EXTENT), QPointF(ttl.x() + _data.tileSize()
+ TEXT_EXTENT, ttl.y() + _data.tileSize() + TEXT_EXTENT));
pointRect &= _bounds;
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.points(pointRectD.toRectC(_projection, 20), _zoom,
&points);
tiles.append(RasterTile(_projection, _transform, &_style, _zoom,
QRect(ttl, QSize(_data.tileSize(), _data.tileSize())),
_tileRatio, paths, points));
} }
} }
} }

View File

@ -189,14 +189,22 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
else else
config.dimensions.append(KV<QString, QString> config.dimensions.append(KV<QString, QString>
(attr.value("id").toString(), reader.readElementText())); (attr.value("id").toString(), reader.readElementText()));
} else if (reader.name() == QLatin1String("header")) {
QXmlStreamAttributes attr = reader.attributes();
if (!attr.hasAttribute("name"))
reader.raiseError("Missing header name");
else
config.headers.append(HTTPHeader(
attr.value("name").toString().toLatin1(),
reader.readElementText().toLatin1()));
} else if (reader.name() == QLatin1String("crs")) { } else if (reader.name() == QLatin1String("crs")) {
config.coordinateSystem = coordinateSystem(reader); config.coordinateSystem = coordinateSystem(reader);
config.crs = reader.readElementText(); config.crs = reader.readElementText();
} else if (reader.name() == QLatin1String("authorization")) { } else if (reader.name() == QLatin1String("authorization")) {
QXmlStreamAttributes attr = reader.attributes(); QXmlStreamAttributes attr = reader.attributes();
config.authorization = Authorization( Authorization auth(attr.value("username").toString(),
attr.value("username").toString(),
attr.value("password").toString()); attr.value("password").toString());
config.headers.append(auth.header());
reader.skipCurrentElement(); reader.skipCurrentElement();
} else if (reader.name() == QLatin1String("tile")) { } else if (reader.name() == QLatin1String("tile")) {
tile(reader, config); tile(reader, config);
@ -252,24 +260,24 @@ Map *MapSource::create(const QString &path, bool *isDir)
case WMTS: case WMTS:
return new WMTSMap(path, config.name, WMTS::Setup(config.url, return new WMTSMap(path, config.name, WMTS::Setup(config.url,
config.layer, config.set, config.style, config.format, config.rest, config.layer, config.set, config.style, config.format, config.rest,
config.coordinateSystem, config.dimensions, config.authorization), config.coordinateSystem, config.dimensions, config.headers),
config.tileRatio); config.tileRatio);
case WMS: case WMS:
return new WMSMap(path, config.name, WMS::Setup(config.url, return new WMSMap(path, config.name, WMS::Setup(config.url,
config.layer, config.style, config.format, config.crs, config.layer, config.style, config.format, config.crs,
config.coordinateSystem, config.dimensions, config.authorization), config.coordinateSystem, config.dimensions, config.headers),
config.tileSize); config.tileSize);
case TMS: case TMS:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, true, false); config.tileSize, config.scalable, true, false);
case OSM: case OSM:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, false, false); config.tileSize, config.scalable, false, false);
case QuadTiles: case QuadTiles:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, false, true); config.tileSize, config.scalable, false, true);
default: default:
return new InvalidMap(path, "Invalid map type"); return new InvalidMap(path, "Invalid map type");

View File

@ -40,7 +40,7 @@ private:
CoordinateSystem coordinateSystem; CoordinateSystem coordinateSystem;
bool rest; bool rest;
QList<KV<QString, QString> > dimensions; QList<KV<QString, QString> > dimensions;
Authorization authorization; QList<HTTPHeader> headers;
qreal tileRatio; qreal tileRatio;
int tileSize; int tileSize;
bool scalable; bool scalable;

View File

@ -10,7 +10,7 @@
OnlineMap::OnlineMap(const QString &fileName, const QString &name, OnlineMap::OnlineMap(const QString &fileName, const QString &name,
const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio, const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable, bool invertY, const QList<HTTPHeader> &headers, int tileSize, bool scalable, bool invertY,
bool quadTiles, QObject *parent) bool quadTiles, QObject *parent)
: Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds), : Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds),
_zoom(_zooms.max()), _tileSize(tileSize), _mapRatio(1.0), _zoom(_zooms.max()), _tileSize(tileSize), _mapRatio(1.0),
@ -19,7 +19,7 @@ OnlineMap::OnlineMap(const QString &fileName, const QString &name,
_tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name), _tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name),
this); this);
_tileLoader->setUrl(url); _tileLoader->setUrl(url);
_tileLoader->setAuthorization(authorization); _tileLoader->setHeaders(headers);
_tileLoader->setQuadTiles(quadTiles); _tileLoader->setQuadTiles(quadTiles);
connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded);
} }

View File

@ -13,7 +13,7 @@ class OnlineMap : public Map
public: public:
OnlineMap(const QString &fileName, const QString &name, const QString &url, OnlineMap(const QString &fileName, const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, qreal tileRatio, const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable, const QList<HTTPHeader> &headers, int tileSize, bool scalable,
bool invertY, bool quadTiles, QObject *parent = 0); bool invertY, bool quadTiles, QObject *parent = 0);
QString name() const {return _name;} QString name() const {return _name;}

View File

@ -17,7 +17,7 @@ public:
const QVariant &zoom() const {return _zoom;} const QVariant &zoom() const {return _zoom;}
const QPoint &xy() const {return _xy;} const QPoint &xy() const {return _xy;}
const RectD &bbox() const {return _bbox;} const RectD &bbox() const {return _bbox;}
QPixmap& pixmap() {return _pixmap;} QPixmap &pixmap() {return _pixmap;}
private: private:
QPoint _xy; QPoint _xy;

View File

@ -61,6 +61,7 @@ TileLoader::TileLoader(const QString &dir, QObject *parent)
connect(_downloader, &Downloader::finished, this, &TileLoader::finished); connect(_downloader, &Downloader::finished, this, &TileLoader::finished);
} }
void TileLoader::loadTilesAsync(QVector<FetchTile> &list) void TileLoader::loadTilesAsync(QVector<FetchTile> &list)
{ {
QList<Download> dl; QList<Download> dl;
@ -87,7 +88,7 @@ void TileLoader::loadTilesAsync(QVector<FetchTile> &list)
} }
if (!dl.empty()) if (!dl.empty())
_downloader->get(dl, _authorization); _downloader->get(dl, _headers);
QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load); QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load);
future.waitForFinished(); future.waitForFinished();
@ -129,7 +130,7 @@ void TileLoader::loadTilesSync(QVector<FetchTile> &list)
if (!dl.empty()) { if (!dl.empty()) {
QEventLoop wait; QEventLoop wait;
connect(_downloader, &Downloader::finished, &wait, &QEventLoop::quit); connect(_downloader, &Downloader::finished, &wait, &QEventLoop::quit);
if (_downloader->get(dl, _authorization)) if (_downloader->get(dl, _headers))
wait.exec(); wait.exec();
for (int i = 0; i < tl.size(); i++) { for (int i = 0; i < tl.size(); i++) {
@ -142,6 +143,11 @@ void TileLoader::loadTilesSync(QVector<FetchTile> &list)
QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load); QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load);
future.waitForFinished(); future.waitForFinished();
for (int i = 0; i < imgs.size(); i++) {
TileImage &ti = imgs[i];
QPixmapCache::insert(ti.file(), ti.tile()->pixmap());
}
} }
void TileLoader::clearCache() void TileLoader::clearCache()

View File

@ -14,8 +14,7 @@ public:
TileLoader(const QString &dir, QObject *parent = 0); TileLoader(const QString &dir, QObject *parent = 0);
void setUrl(const QString &url) {_url = url;} void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization) void setHeaders(const QList<HTTPHeader> &headers) {_headers = headers;}
{_authorization = authorization;}
void setScaledSize(int size); void setScaledSize(int size);
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;} void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
@ -33,7 +32,7 @@ private:
Downloader *_downloader; Downloader *_downloader;
QString _url; QString _url;
QString _dir; QString _dir;
Authorization _authorization; QList<HTTPHeader> _headers;
int _scaledSize; int _scaledSize;
bool _quadTiles; bool _quadTiles;
}; };

View File

@ -345,7 +345,7 @@ WMS::WMS(const QString &file, const WMS::Setup &setup, QObject *parent)
QList<Download> dl; QList<Download> dl;
dl.append(Download(url, _path)); dl.append(Download(url, _path));
_valid = downloader->get(dl, _setup.authorization()); _valid = downloader->get(dl, _setup.headers());
} else { } else {
_ready = true; _ready = true;
_valid = parseCapabilities(); _valid = parseCapabilities();

View File

@ -23,13 +23,13 @@ public:
Setup(const QString &url, const QString &layer, const QString &style, Setup(const QString &url, const QString &layer, const QString &style,
const QString &format, const QString &crs, const CoordinateSystem &cs, const QString &format, const QString &crs, const CoordinateSystem &cs,
const QList<KV<QString, QString> > &dimensions, const QList<KV<QString, QString> > &dimensions,
const Authorization &authorization = Authorization()) const QList<HTTPHeader> &headers)
: _url(url), _layer(layer), _style(style), _format(format), : _url(url), _layer(layer), _style(style), _format(format),
_crs(crs), _cs(cs), _dimensions(dimensions), _crs(crs), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {} _headers(headers) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;} const QList<HTTPHeader> &headers() const {return _headers;}
const QString &layer() const {return _layer;} const QString &layer() const {return _layer;}
const QString &style() const {return _style;} const QString &style() const {return _style;}
const QString &format() const {return _format;} const QString &format() const {return _format;}
@ -46,7 +46,7 @@ public:
QString _crs; QString _crs;
CoordinateSystem _cs; CoordinateSystem _cs;
QList<KV<QString, QString> > _dimensions; QList<KV<QString, QString> > _dimensions;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };

View File

@ -74,7 +74,7 @@ WMSMap::WMSMap(const QString &fileName, const QString &name,
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
_tileLoader = new TileLoader(tilesDir, this); _tileLoader = new TileLoader(tilesDir, this);
_tileLoader->setAuthorization(setup.authorization()); _tileLoader->setHeaders(setup.headers());
connect(_tileLoader, &TileLoader::finished, this, &WMSMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &WMSMap::tilesLoaded);
_wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); _wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);

View File

@ -361,7 +361,7 @@ WMTS::WMTS(const QString &file, const WMTS::Setup &setup, QObject *parent)
QList<Download> dl; QList<Download> dl;
dl.append(Download(url.toString(), _path)); dl.append(Download(url.toString(), _path));
_valid = downloader->get(dl, _setup.authorization()); _valid = downloader->get(dl, _setup.headers());
} else { } else {
_ready = true; _ready = true;
_valid = init(); _valid = init();

View File

@ -27,13 +27,13 @@ public:
const QString &style, const QString &format, bool rest, const QString &style, const QString &format, bool rest,
const CoordinateSystem &cs, const CoordinateSystem &cs,
const QList<KV<QString, QString> > &dimensions, const QList<KV<QString, QString> > &dimensions,
const Authorization &authorization = Authorization()) const QList<HTTPHeader> &headers)
: _url(url), _layer(layer), _set(set), _style(style), : _url(url), _layer(layer), _set(set), _style(style),
_format(format), _rest(rest), _cs(cs), _dimensions(dimensions), _format(format), _rest(rest), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {} _headers(headers) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;} const QList<HTTPHeader> &headers() const {return _headers;}
const QString &layer() const {return _layer;} const QString &layer() const {return _layer;}
const QString &set() const {return _set;} const QString &set() const {return _set;}
const QString &style() const {return _style;} const QString &style() const {return _style;}
@ -52,7 +52,7 @@ public:
bool _rest; bool _rest;
CoordinateSystem _cs; CoordinateSystem _cs;
QList<KV<QString, QString> > _dimensions; QList<KV<QString, QString> > _dimensions;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };
class Zoom class Zoom

View File

@ -20,7 +20,7 @@ WMTSMap::WMTSMap(const QString &fileName, const QString &name,
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
_tileLoader = new TileLoader(tilesDir, this); _tileLoader = new TileLoader(tilesDir, this);
_tileLoader->setAuthorization(setup.authorization()); _tileLoader->setHeaders(setup.headers());
connect(_tileLoader, &TileLoader::finished, this, &WMTSMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &WMTSMap::tilesLoaded);
_wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); _wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);