1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-04 14:49:30 +02:00

Compare commits

..

28 Commits
13.2 ... 13.4

Author SHA1 Message Date
9afeaf672a Properly match symbols to captions 2023-06-10 08:11:18 +02:00
5ddd63e697 Do not limit text that was not inserted 2023-06-06 07:32:42 +02:00
88fa1ed786 Some more Mapsforge maps rendering improvements 2023-06-06 07:18:31 +02:00
1233d20a21 Added support for lineSymbols in Mapsforge maps 2023-06-04 23:56:00 +02:00
1746eddb8d Code cleanup 2023-06-03 13:35:29 +02:00
ecda5103c8 Properly handle Mapsforge style menus 2023-05-31 01:01:42 +02:00
50b0ff1c56 Cosmetics 2023-05-29 23:19:28 +02:00
2b300fab54 Code cleanup 2023-05-29 23:19:16 +02:00
961061b643 Added rescue station 2023-05-28 11:28:12 +02:00
8bebea53ad Added LNDELV elevation values 2023-05-28 10:40:39 +02:00
c3b484bb75 Properly include std::isnan() 2023-05-26 21:57:45 +02:00
d6d43baec5 Optimization 2023-05-26 21:30:27 +02:00
c6c3e0978c Use generic icon rotate instead of special icon draw functions 2023-05-26 21:28:44 +02:00
320b04c3fa Added support for line "dy" parameter 2023-05-22 23:29:04 +02:00
ab7185bd25 Version++ 2023-05-22 23:28:50 +02:00
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
53 changed files with 1108 additions and 666 deletions

View File

@ -1,4 +1,4 @@
version: 13.2.{build}
version: 13.4.{build}
configuration:
- Release

View File

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

View File

@ -198,6 +198,9 @@
<file alias="building.png">icons/map/marine/building.png</file>
<file alias="fog-signal.png">icons/map/marine/fog-signal.png</file>
<file alias="construction.png">icons/map/marine/construction.png</file>
<file alias="radio-call.png">icons/map/marine/radio-call.png</file>
<file alias="current.png">icons/map/marine/current.png</file>
<file alias="rescue-station.png">icons/map/marine/rescue-station.png</file>
</qresource>
<!-- Mapsforge rendertheme -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@ -712,7 +712,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>CRS-katalog:</translation>
</message>
<message>
<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="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>Dossier CRS:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="915"/>
@ -1427,12 +1427,12 @@
<message>
<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>
<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>
<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>
<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>
<location filename="../src/GUI/optionsdialog.cpp" line="77"/>
@ -1912,7 +1912,7 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="758"/>
<source>DEM cache size:</source>
<translation type="unfinished"></translation>
<translation>Taille du cache DEM :</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="778"/>

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "13.2"
!define VERSION "13.4"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
template <class KEY, class VALUE>
class KV {
public:
KV() {}
KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {}
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
@ -97,3 +97,11 @@ QString DEMLoader::tileFile(const DEM::Tile &tile) const
{
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);
void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization)
{_authorization = authorization;}
void setAuthorization(const Authorization &authorization);
bool loadTiles(const RectC &rect);
bool checkTiles(const RectC &rect) const;
@ -34,7 +33,7 @@ private:
Downloader *_downloader;
QString _url;
QDir _dir;
Authorization _authorization;
QList<HTTPHeader> _headers;
};
#endif // DEMLOADER_H

View File

@ -23,6 +23,7 @@ static QMap<uint,uint> orderMapInit()
map.insert(TYPE(FOGSIG), 0);
map.insert(TYPE(CGUSTA), 1);
map.insert(TYPE(RSCSTA), 1);
map.insert(SUBTYPE(BUAARE, 1), 2);
map.insert(SUBTYPE(BUAARE, 5), 3);
map.insert(SUBTYPE(BUAARE, 4), 4);
@ -264,6 +265,13 @@ MapData::Point::Point(uint type, const Coordinates &c, const QString &label,
if (_label.isEmpty())
_label = sistat(type & 0xFF);
_type = TYPE(SISTAT);
} else if (type>>16 == LNDELV && params.size()) {
if (_label.isEmpty())
_label = QString::fromLatin1(params.at(0))
+ QString::fromUtf8("\xE2\x80\x89m");
else
_label += "\n(" + QString::fromLatin1(params.at(0))
+ "\xE2\x80\x89m)";
}
}
@ -552,7 +560,8 @@ MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL)
if ((OBJL == I_DISMAR && key == I_WTWDIS)
|| (OBJL == RDOCAL && key == ORIENT)
|| (OBJL == I_RDOCAL && key == ORIENT)
|| (OBJL == CURENT && key == ORIENT))
|| (OBJL == CURENT && key == ORIENT)
|| (OBJL == LNDELV && key == ELEVAT))
params[0] = av.at(1).toByteArray();
if ((OBJL == I_RDOCAL && key == COMCHA)
|| (OBJL == RDOCAL && key == COMCHA)
@ -893,7 +902,7 @@ void MapData::clear()
_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];
@ -901,7 +910,7 @@ void MapData::points(const RectC &rect, QList<Point*> *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];
@ -909,7 +918,7 @@ void MapData::lines(const RectC &rect, QList<Line*> *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];

View File

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

View File

@ -70,6 +70,7 @@
#define RAILWY 106
#define RCRTCL 108
#define RECTRC 109
#define RSCSTA 111
#define RESARE 112
#define RIVERS 114
#define ROADWY 116

View File

@ -3,19 +3,18 @@
#include "common/linec.h"
#include "map/bitmapline.h"
#include "map/textpathitem.h"
#include "map/rectd.h"
#include "style.h"
#include "rastertile.h"
using namespace ENC;
#define TEXT_EXTENT 160
#define TSSLPT_SIZE 0.005 /* ll */
#define RDOCAL_SIZE 12 /* px */
#define CURENT_SIZE 12 /* px */
typedef QMap<Coordinates, const MapData::Point*> PointMap;
const float C1 = 0.866025f; /* sqrt(3)/2 */
static const float C1 = 0.866025f; /* sqrt(3)/2 */
static const QColor haloColor(Qt::white);
static struct {
@ -102,67 +101,12 @@ static Coordinates centroid(const QVector<Coordinates> &polygon)
return Coordinates(cx * factor, cy * factor);
}
static QImage *rdocalArrow(qreal angle)
static double angle(uint type, const QVariant &param)
{
QImage *img = new QImage(RDOCAL_SIZE*2, RDOCAL_SIZE*2,
QImage::Format_ARGB32_Premultiplied);
img->fill(Qt::transparent);
QPainter p(img);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(QPen(QColor("#eb49eb"), 1));
uint bt = type>>16;
QPointF arrow[3];
arrow[0] = QPointF(img->width()/2, img->height()/2);
arrow[1] = arrow[0] + QPointF(qSin(angle - M_PI/3) * RDOCAL_SIZE,
qCos(angle - M_PI/3) * RDOCAL_SIZE);
arrow[2] = arrow[0] + QPointF(qSin(angle - M_PI + M_PI/3) * RDOCAL_SIZE,
qCos(angle - M_PI + M_PI/3) * RDOCAL_SIZE);
QLineF l(arrow[1], arrow[2]);
QPointF pt(l.pointAt(0.5));
p.translate(arrow[0] - pt);
p.drawPolyline(QPolygonF() << arrow[1] << arrow[0] << arrow[2]);
p.drawEllipse(pt, RDOCAL_SIZE/2, RDOCAL_SIZE/2);
return img;
}
static QImage *currentArrow(qreal angle)
{
QImage *img = new QImage(CURENT_SIZE*2, CURENT_SIZE*2,
QImage::Format_ARGB32_Premultiplied);
img->fill(Qt::transparent);
QPainter p(img);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(QPen(Qt::black, 1));
QPointF arrow[3];
arrow[0] = QPointF(img->width()/2, img->height()/2);
arrow[1] = arrow[0] + QPointF(qSin(angle - M_PI/3) * CURENT_SIZE,
qCos(angle - M_PI/3) * CURENT_SIZE);
arrow[2] = arrow[0] + QPointF(qSin(angle - M_PI + M_PI/3) * CURENT_SIZE,
qCos(angle - M_PI + M_PI/3) * CURENT_SIZE);
QLineF l(arrow[1], arrow[2]);
QPointF pt(l.pointAt(0.5));
QLineF l2(arrow[0], pt);
p.translate(arrow[0] - pt);
p.drawPolyline(QPolygonF() << arrow[1] << arrow[0] << arrow[2]);
p.drawLine(arrow[0], l2.pointAt(2));
return img;
}
static QImage *image(uint type, const QVariant &param)
{
if (type>>16 == RDOCAL || type>>16 == I_RDOCAL)
return rdocalArrow(deg2rad(90 - param.toDouble()));
else if (type>>16 == CURENT)
return currentArrow(deg2rad(90 - param.toDouble()));
else
return 0;
return (bt == RDOCAL || bt == I_RDOCAL || bt == CURENT)
? 90 + param.toDouble() : NAN;
}
static bool showLabel(const QImage *img, const Range &range, int zoom, int type)
@ -183,9 +127,10 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon) const
for (int i = 0; i < polygon.size(); i++) {
const QVector<Coordinates> &subpath = polygon.at(i);
path.moveTo(ll2xy(subpath.first()));
for (int j = 1; j < subpath.size(); j++)
path.lineTo(ll2xy(subpath.at(j)));
QVector<QPointF> p(subpath.size());
for (int j = 0; j < subpath.size(); j++)
p[j] = ll2xy(subpath.at(j));
path.addPolygon(p);
}
return path;
@ -227,10 +172,11 @@ QPolygonF RasterTile::tsslptArrow(const Coordinates &c, qreal angle) const
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++) {
const MapData::Poly *poly = _polygons.at(i);
for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly *poly = polygons.at(i);
if (poly->type()>>16 == TSSLPT) {
QPolygonF polygon(tsslptArrow(centroid(poly->path().first()),
@ -243,13 +189,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();
for (int n = 0; n < s.drawOrder().size(); n++) {
for (int i = 0; i < _polygons.size(); i++) {
const MapData::Poly *poly = _polygons.at(i);
for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly *poly = polygons.at(i);
if (poly->type() != s.drawOrder().at(n))
continue;
const Style::Polygon &style = s.polygon(poly->type());
@ -267,14 +214,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();
painter->setBrush(Qt::NoBrush);
for (int i = 0; i < _lines.size(); i++) {
const MapData::Line *line = _lines.at(i);
for (int i = 0; i < lines.size(); i++) {
const MapData::Line *line = lines.at(i);
const Style::Line &style = s.line(line->type());
if (!style.img().isNull()) {
@ -293,12 +240,13 @@ void RasterTile::drawTextItems(QPainter *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();
for (int i = 0; i < _polygons.size(); i++) {
const MapData::Poly *poly = _polygons.at(i);
for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly *poly = polygons.at(i);
uint type = poly->type()>>16;
if (!(type == HRBFAC || type == I_TRNBSN
@ -319,18 +267,18 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
}
}
void RasterTile::processPoints(QList<TextItem*> &textItems,
QList<TextItem*> &lights)
void RasterTile::processPoints(QList<MapData::Point*> &points,
QList<TextItem*> &textItems, QList<TextItem*> &lights)
{
const Style &s = style();
PointMap lightsMap, signalsMap;
int i;
std::sort(_points.begin(), _points.end(), pointLess);
std::sort(points.begin(), points.end(), pointLess);
/* Lights & Signals */
for (i = 0; i < _points.size(); i++) {
const MapData::Point *point = _points.at(i);
for (i = 0; i < points.size(); i++) {
const MapData::Point *point = points.at(i);
if (point->type()>>16 == LIGHTS)
lightsMap.insert(point->pos(), point);
else if (point->type()>>16 == FOGSIG)
@ -340,26 +288,25 @@ void RasterTile::processPoints(QList<TextItem*> &textItems,
}
/* Everything else */
for ( ; i < _points.size(); i++) {
const MapData::Point *point = _points.at(i);
for ( ; i < points.size(); i++) {
const MapData::Point *point = points.at(i);
QPoint pos(ll2xy(point->pos()).toPoint());
const Style::Point &style = s.point(point->type());
const QString *label = point->label().isEmpty() ? 0 : &(point->label());
QImage *rimg = style.img().isNull()
? image(point->type(), point->param()) : 0;
const QImage *img = style.img().isNull() ? rimg : &style.img();
const QFont *fnt = showLabel(img, _zooms, _zoom, point->type())
const QImage *img = style.img().isNull() ? 0 : &style.img();
const QFont *fnt = showLabel(img, _data->zooms(), _zoom, point->type())
? font(style.textFontSize()) : 0;
const QColor *color = &style.textColor();
const QColor *hColor = style.haloColor().isValid()
? &style.haloColor() : 0;
double rotate = angle(point->type(), point->param());
if ((!label || !fnt) && !img)
continue;
PointItem *item = new PointItem(pos, label, fnt, img, rimg, color,
hColor);
TextPointItem *item = new TextPointItem(pos, label, fnt, img, color,
hColor, 0, 2, rotate);
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (lightsMap.contains(point->pos()))
@ -371,12 +318,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();
for (int i = 0; i < _lines.size(); i++) {
const MapData::Line *line = _lines.at(i);
for (int i = 0; i < lines.size(); i++) {
const MapData::Line *line = lines.at(i);
const Style::Line &style = s.line(line->type());
if (style.img().isNull() && style.pen() == Qt::NoPen)
@ -396,25 +344,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()
{
QList<MapData::Line*> lines;
QList<MapData::Poly*> polygons;
QList<MapData::Point*> points;
QList<TextItem*> textItems, lights;
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
processPolygons(textItems);
processPoints(textItems, lights);
processLines(textItems);
fetchData(polygons, lines, points);
processPolygons(polygons, textItems);
processPoints(points, textItems, lights);
processLines(lines, textItems);
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y());
drawPolygons(&painter);
drawLines(&painter);
drawArrows(&painter);
drawPolygons(&painter, polygons);
drawLines(&painter, lines);
drawArrows(&painter, polygons);
drawTextItems(&painter, lights);
drawTextItems(&painter, textItems);

View File

@ -15,13 +15,10 @@ class RasterTile
{
public:
RasterTile(const Projection &proj, const Transform &transform,
const Range &zooms, int zoom, const QRect &rect, qreal ratio,
const QList<MapData::Line*> &lines, const QList<MapData::Poly*> &polygons,
const QList<MapData::Point*> &points)
: _proj(proj), _transform(transform), _zooms(zooms), _zoom(zoom),
const MapData *data, int zoom, const QRect &rect, qreal ratio)
: _proj(proj), _transform(transform), _data(data), _zoom(zoom),
_rect(rect), _ratio(ratio),
_pixmap(rect.width() * ratio, rect.height() * ratio), _lines(lines),
_polygons(polygons), _points(points), _valid(false) {}
_pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
int zoom() const {return _zoom;}
QPoint xy() const {return _rect.topLeft();}
@ -31,44 +28,33 @@ public:
void render();
private:
class PointItem : public TextPointItem
{
public:
PointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QImage *rimg, const QColor *color,
const QColor *haloColor) : TextPointItem(point, text, font, img, color,
haloColor, 0, 2), _rimg(rimg) {}
~PointItem() {delete _rimg;}
private:
const QImage *_rimg;
};
void fetchData(QList<MapData::Poly*> &polygons, QList<MapData::Line*> &lines,
QList<MapData::Point*> &points);
QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));}
QPainterPath painterPath(const Polygon &polygon) const;
QPolygonF polyline(const QVector<Coordinates> &path) const;
QPolygonF tsslptArrow(const Coordinates &c, qreal angle) const;
void processPoints(QList<TextItem*> &textItems, QList<TextItem *> &lights);
void processLines(QList<TextItem*> &textItems);
void processPolygons(QList<TextItem*> &textItems);
void processPoints(QList<MapData::Point *> &points,
QList<TextItem*> &textItems, QList<TextItem *> &lights);
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,
const Polygon &polygon);
void drawArrows(QPainter *painter);
void drawPolygons(QPainter *painter);
void drawLines(QPainter *painter);
void drawArrows(QPainter *painter, const QList<MapData::Poly*> &polygons);
void drawPolygons(QPainter *painter, const QList<MapData::Poly *> &polygons);
void drawLines(QPainter *painter, const QList<MapData::Line *> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
Projection _proj;
Transform _transform;
Range _zooms;
const MapData *_data;
int _zoom;
QRect _rect;
qreal _ratio;
QPixmap _pixmap;
QList<MapData::Line*> _lines;
QList<MapData::Poly*> _polygons;
QList<MapData::Point*> _points;
bool _valid;
};

View File

@ -248,6 +248,7 @@ void Style::pointStyle()
_points[SUBTYPE(I_DISMAR, 3)] = _points[SUBTYPE(I_DISMAR, 2)];
_points[SUBTYPE(I_DISMAR, 4)] = _points[SUBTYPE(I_DISMAR, 2)];
_points[TYPE(CGUSTA)] = Point(QImage(":/marine/coast-guard.png"));
_points[TYPE(RSCSTA)] = Point(QImage(":/marine/rescue-station.png"));
_points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png"));
_points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png"));
_points[TYPE(RTPBCN)] = Point(QImage(":/marine/radar-transponder.png"));
@ -255,7 +256,9 @@ void Style::pointStyle()
_points[TYPE(I_TRNBSN)] = Point(QImage(":/marine/turning-basin.png"));
_points[TYPE(I_TRNBSN)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_WTWGAG)] = Point(QImage(":/marine/gauge.png"), Small);
_points[TYPE(RDOCAL)] = Point(QImage(":/marine/radio-call.png"));
_points[TYPE(RDOCAL)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_RDOCAL)] = Point(QImage(":/marine/radio-call.png"));
_points[TYPE(I_RDOCAL)].setTextColor(QColor("#eb49eb"));
_points[TYPE(PYLONS)] = Point(QImage(":/marine/pylon.png"));
_points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"));
@ -265,6 +268,7 @@ void Style::pointStyle()
_points[TYPE(PILBOP)] = Point(QImage(":/marine/boarding-place.png"));
_points[TYPE(SISTAT)] = Point(QImage(":/marine/pylon.png"));
_points[TYPE(SLCONS)] = Point(QImage(":/marine/construction.png"), Small);
_points[TYPE(CURENT)] = Point(QImage(":/marine/current.png"));
_points[SUBTYPE(SMCFAC, 7)] = Point(QImage(":/POI/restaurant-11.png"), Small);
_points[SUBTYPE(SMCFAC, 11)] = Point(QImage(":/POI/pharmacy-11.png"), Small);

View File

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

View File

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

View File

@ -5,12 +5,14 @@
#include "map/textpathitem.h"
#include "map/textpointitem.h"
#include "map/bitmapline.h"
#include "map/rectd.h"
#include "style.h"
#include "lblfile.h"
#include "rastertile.h"
using namespace IMG;
#define TEXT_EXTENT 160
#define ICON_PADDING 2
#define AREA(rect) \
@ -147,40 +149,6 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|| 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)
{
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);
for (int n = 0; n < _style->drawOrder().size(); n++) {
for (int i = 0; i < _polygons.size(); i++) {
const MapData::Poly &poly = _polygons.at(i);
if (poly.type != _style->drawOrder().at(n))
for (int n = 0; n < _data->style()->drawOrder().size(); n++) {
for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly &poly = polygons.at(i);
if (poly.type != _data->style()->drawOrder().at(n))
continue;
if (poly.raster.isValid()) {
@ -237,7 +206,7 @@ void RasterTile::drawPolygons(QPainter *painter)
//painter->setBrush(Qt::NoBrush);
//painter->drawRect(QRectF(tl, br));
} else {
const Style::Polygon &style = _style->polygon(poly.type);
const Style::Polygon &style = _data->style()->polygon(poly.type);
painter->setPen(style.pen());
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);
for (int i = 0; i < _lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i);
const Style::Line &style = _style->line(poly.type);
for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _data->style()->line(poly.type);
if (style.background() == Qt::NoPen)
continue;
@ -262,9 +231,9 @@ void RasterTile::drawLines(QPainter *painter)
painter->drawPolyline(poly.points);
}
for (int i = 0; i < _lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i);
const Style::Line &style = _style->line(poly.type);
for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _data->style()->line(poly.type);
if (!style.img().isNull())
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;
QList<TextItem *> labels;
for (int i = 0; i < _polygons.size(); i++) {
const MapData::Poly &poly = _polygons.at(i);
for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly &poly = polygons.at(i);
bool exists = set.contains(poly.label.text());
if (poly.label.text().isEmpty())
@ -310,7 +280,7 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
if (_zoom <= 23 && (Style::isWaterArea(poly.type)
|| Style::isMilitaryArea(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(
centroid(poly.points).toPoint(), &poly.label.text(), poiFont(),
0, &style.brush().color(), &haloColor);
@ -331,20 +301,22 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
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)
processStreetNames(textItems);
processShields(textItems);
processStreetNames(lines, 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++) {
const MapData::Poly &poly = _lines.at(i);
const Style::Line &style = _style->line(poly.type);
for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _data->style()->line(poly.type);
if (style.img().isNull() && style.foreground() == Qt::NoPen)
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++) {
if (minShieldZoom(static_cast<Shield::Type>(type)) > _zoom)
@ -375,8 +348,8 @@ void RasterTile::processShields(QList<TextItem*> &textItems)
QHash<Shield, QPolygonF> shields;
QHash<Shield, const Shield*> sp;
for (int i = 0; i < _lines.size(); i++) {
const MapData::Poly &poly = _lines.at(i);
for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = lines.at(i);
const Shield &shield = poly.label.shield();
if (!shield.isValid() || shield.type() != 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++) {
const MapData::Point &point = _points.at(i);
const Style::Point &style = _style->point(point.type);
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
const Style::Point &style = _data->style()->point(point.type);
bool poi = Style::isPOI(point.type);
const QString *label = point.label.text().isEmpty()
@ -461,3 +435,60 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
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(_rect);
}

View File

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

View File

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

View File

@ -29,10 +29,10 @@ public:
void polys(const RectC &rect, const Zoom &zoom,
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,
QList<MapData::Point> *points, QCache<const SubDiv*,
QList<MapData::Point> > *pointCache);
QList<MapData::Point> > *pointCache, QMutex *lock);
static bool isTileFile(SubFile::Type type)
{

View File

@ -6,11 +6,10 @@
#include "pcs.h"
#include "encmap.h"
#define TILE_SIZE 512
#define TEXT_EXTENT 160
using namespace ENC;
#define TILE_SIZE 512
ENCMap::ENCMap(const QString &fileName, QObject *parent)
: 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;
if (QPixmapCache::find(key(_zoom, ttl), &pm))
painter->drawPixmap(ttl, pm);
else {
QList<MapData::Poly*> polygons;
QList<MapData::Line*> lines;
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));
}
else
tiles.append(RasterTile(_projection, _transform, &_data,
_zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio));
}
}

View File

@ -16,7 +16,6 @@
using namespace IMG;
#define TILE_SIZE 384
#define TEXT_EXTENT 160
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))
painter->drawPixmap(ttl, pm);
else {
QList<MapData::Poly> polygons, lines;
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()));
_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));
tiles.append(RasterTile(_projection, _transform, _data.at(n),
_zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio,
key));
}
}
}

View File

@ -23,17 +23,21 @@ using namespace Mapsforge;
static void copyPaths(const RectC &rect, const QList<MapData::Path> *src,
QList<MapData::Path> *dst)
{
for (int i = 0; i < src->size(); i++)
if (rect.intersects(src->at(i).poly.boundingRect()))
dst->append(src->at(i));
for (int i = 0; i < src->size(); i++) {
const MapData::Path &path = src->at(i);
if (rect.intersects(path.poly.boundingRect()))
dst->append(path);
}
}
static void copyPoints(const RectC &rect, const QList<MapData::Point> *src,
QList<MapData::Point> *dst)
{
for (int i = 0; i < src->size(); i++)
if (rect.contains(src->at(i).coordinates))
dst->append(src->at(i));
for (int i = 0; i < src->size(); i++) {
const MapData::Point &point = src->at(i);
if (rect.contains(point.coordinates))
dst->append(point);
}
}
static double distance(const Coordinates &c1, const Coordinates &c2)
@ -208,13 +212,15 @@ bool MapData::readTags(SubFile &subfile, int count,
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++) {
const SubFileInfo &f = _subFiles.at(i);
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 br(OSM::ll2tile(_bounds.bottomRight(), f.base));
@ -359,7 +365,7 @@ bool MapData::readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap)
return true;
}
bool MapData::readHeader()
bool MapData::readHeader(QFile &file)
{
char magic[MAGIC_SIZE];
quint32 hdrSize;
@ -367,18 +373,18 @@ bool MapData::readHeader()
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)) {
_errorString = "Not a Mapsforge map";
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";
return false;
}
SubFile hdr(_file, MAGIC_SIZE, qFromBigEndian(hdrSize));
SubFile hdr(file, MAGIC_SIZE, qFromBigEndian(hdrSize));
if (!readMapInfo(hdr, projection, debugMap)) {
_errorString = "Error reading map info";
@ -407,18 +413,19 @@ bool MapData::readHeader()
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)) {
_errorString = _file.errorString();
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QIODevice::Unbuffered)) {
_errorString = file.errorString();
return;
}
if (!readHeader())
if (!readHeader(file))
return;
_file.close();
_pathCache.setMaxCost(256);
_pointCache.setMaxCost(256);
@ -444,13 +451,16 @@ RectC MapData::bounds() const
void MapData::load()
{
if (_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered))
readSubFiles();
_pointFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
_pathFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
readSubFiles();
}
void MapData::clear()
{
_file.close();
_pointFile.close();
_pathFile.close();
_pathCache.clear();
_pointCache.clear();
@ -497,6 +507,9 @@ int MapData::level(int zoom) const
void MapData::points(const RectC &rect, int zoom, QList<Point> *list)
{
if (!rect.isValid())
return;
int l(level(zoom));
PointCTX ctx(this, rect, zoom, list);
double min[2], max[2];
@ -513,6 +526,9 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
QList<Point> *list)
{
Key key(tile, zoom);
_pointLock.lock();
QList<Point> *cached = _pointCache.object(key);
if (!cached) {
@ -524,18 +540,24 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
delete p;
} else
copyPoints(rect, cached, list);
_pointLock.unlock();
}
void MapData::paths(const RectC &rect, int zoom, QList<Path> *list)
void MapData::paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
QList<Path> *list)
{
if (!searchRect.isValid())
return;
int l(level(zoom));
PathCTX ctx(this, rect, zoom, list);
PathCTX ctx(this, boundsRect, zoom, list);
double min[2], max[2];
min[0] = rect.left();
min[1] = rect.bottom();
max[0] = rect.right();
max[1] = rect.top();
min[0] = searchRect.left();
min[1] = searchRect.bottom();
max[0] = searchRect.right();
max[1] = searchRect.top();
_tiles.at(l)->Search(min, max, pathCb, &ctx);
}
@ -544,6 +566,9 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
QList<Path> *list)
{
Key key(tile, zoom);
_pathLock.lock();
QList<Path> *cached = _pathCache.object(key);
if (!cached) {
@ -555,12 +580,14 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
delete p;
} else
copyPaths(rect, cached, list);
_pathLock.unlock();
}
bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
{
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;
QVector<unsigned> paths(rows);
quint32 blocks, unused, val, cnt = 0;
@ -584,8 +611,10 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
if (!subfile.seek(subfile.pos() + val))
return false;
paths.reserve(paths[zoom - info.min]);
for (unsigned i = 0; i < paths[zoom - info.min]; i++) {
Path p(subfile.offset() + subfile.pos());
Path p;
qint32 lon = 0, lat = 0;
if (!(subfile.readVUInt32(unused) && subfile.readUInt16(bitmap)
@ -644,7 +673,7 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
{
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;
QVector<unsigned> points(rows);
quint32 val, unused, cnt = 0;
@ -665,6 +694,8 @@ bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
if (!subfile.readVUInt32(unused))
return false;
list->reserve(points[zoom - info.min]);
for (unsigned i = 0; i < points[zoom - info.min]; i++) {
qint32 lat, lon;

View File

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

View File

@ -1,10 +1,18 @@
#include <cmath>
#include <QPainter>
#include <QCache>
#include "common/programpaths.h"
#include "map/rectd.h"
#include "rastertile.h"
using namespace Mapsforge;
#define TEXT_EXTENT 160
#define PATHS_EXTENT 20
#define SEARCH_EXTENT -0.5
static double limit = cos(deg2rad(170));
static qreal area(const QPainterPath &polygon)
{
qreal area = 0;
@ -52,44 +60,89 @@ static const QColor *haloColor(const Style::TextRender *ti)
? &ti->strokeColor() : 0;
}
void RasterTile::processPointLabels(QList<TextItem*> &textItems)
static QPainterPath parallelPath(const QPainterPath &p, double dy)
{
int n = p.elementCount() - 1;
QVector<QPointF> u(n);
QPainterPath h;
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
h.reserve(p.elementCount());
#endif // QT 5.13
for (int k = 0; k < n; k++) {
qreal c = p.elementAt(k + 1).x - p.elementAt(k).x;
qreal s = p.elementAt(k + 1).y - p.elementAt(k).y;
qreal l = sqrt(c * c + s * s);
u[k] = (l == 0) ? QPointF(0, 0) : QPointF(c / l, s / l);
if (k == 0)
continue;
if (u.at(k).x() * u.at(k-1).x() + u.at(k).y() * u.at(k-1).y() < limit)
return p;
}
h.moveTo(QPointF(p.elementAt(0).x - dy * u.at(0).y(),
p.elementAt(0).y + dy * u.at(0).x()));
for (int k = 1; k < n; k++) {
qreal l = dy / (1 + u.at(k).x() * u.at(k-1).x()
+ u.at(k).y() * u.at(k-1).y());
QPainterPath::Element e(p.elementAt(k));
h.lineTo(QPointF(e.x - l * (u.at(k).y() + u.at(k-1).y()),
e.y + l * (u.at(k).x() + u.at(k-1).x())));
}
h.lineTo(QPointF(p.elementAt(n).x - dy * u.at(n-1).y(),
p.elementAt(n).y + dy * u.at(n-1).x()));
return h;
}
void RasterTile::processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->pointLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->pointSymbols(_zoom));
QList<PainterPoint> points;
QList<PointText> items;
for (int i = 0; i < _points.size(); i++) {
const MapData::Point &point = _points.at(i);
const QByteArray *lbl = 0;
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.tags))
if (!si || si->priority() < ri->priority())
si = ri;
}
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(point.tags)) {
if ((lbl = label(ri->key(), point.tags))) {
if (si && si->id() != ri->symbolId())
continue;
ti = ri;
break;
}
}
}
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.tags)) {
si = ri;
break;
}
}
if (ti || si)
points.append(PainterPoint(&point, lbl, si, ti));
items.append(PointText(&point, lbl, si, ti));
}
std::sort(points.begin(), points.end());
std::sort(items.begin(), items.end());
for (int i = 0; i < points.size(); i++) {
const PainterPoint &p = points.at(i);
for (int i = 0; i < items.size(); i++) {
const PointText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
@ -104,14 +157,15 @@ void RasterTile::processPointLabels(QList<TextItem*> &textItems)
}
}
void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths)
void RasterTile::processAreaLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->areaLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->areaSymbols(_zoom));
QList<PathText> items;
for (int i = 0; i < paths.size(); i++) {
PainterPath &path = paths[i];
const PainterPath &path = paths.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
@ -119,6 +173,69 @@ void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
if (!path.path->closed)
continue;
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(path.path->closed, path.path->tags))
if (!si || si->priority() < ri->priority())
si = ri;
}
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
if ((lbl = label(ri->key(), path.path->tags))) {
if (si && si->id() != ri->symbolId())
continue;
ti = ri;
break;
}
}
}
if (ti || si)
items.append(PathText(&path, lbl, si, ti));
}
std::sort(items.begin(), items.end());
for (int i = 0; i < items.size(); i++) {
const PathText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
const QColor *hColor = p.ti ? haloColor(p.ti) : 0;
QPointF pos = p.p->path->labelPos.isNull()
? centroid(p.p->pp) : ll2xy(p.p->path->labelPos);
PointItem *item = new PointItem(pos.toPoint(), p.lbl, font, img, color,
hColor);
if (item->isValid() && _rect.contains(item->boundingRect().toRect())
&& !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->pathLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->lineSymbols(_zoom));
QList<PathText> items;
QSet<QByteArray> set;
for (int i = 0; i < paths.size(); i++) {
const PainterPath &path = paths.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
if (path.path->closed)
continue;
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
@ -130,61 +247,50 @@ void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(path.path->tags)) {
if (ri->rule().match(path.path->closed, path.path->tags)) {
si = ri;
break;
}
}
if (!ti && !si)
continue;
const QImage *img = si ? &si->img() : 0;
const QFont *font = ti ? &ti->font() : 0;
const QColor *color = ti ? &ti->fillColor() : 0;
const QColor *hColor = ti ? haloColor(ti) : 0;
QPointF pos = path.path->labelPos.isNull()
? centroid(path.pp) : ll2xy(path.path->labelPos);
PointItem *item = new PointItem(pos.toPoint(), lbl, font, img, color,
hColor);
if (item->isValid() && _rect.contains(item->boundingRect().toRect())
&& !item->collides(textItems))
textItems.append(item);
else
delete item;
if (ti || si)
items.append(PathText(&path, lbl, si, ti));
}
}
void RasterTile::processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths)
{
QList<const Style::TextRender*> instructions(_style->pathLabels(_zoom));
QSet<QByteArray> set;
std::sort(items.begin(), items.end());
for (int i = 0; i < instructions.size(); i++) {
const Style::TextRender *ri = instructions.at(i);
for (int i = 0; i < items.size(); i++) {
const PathText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
const QColor *hColor = p.ti ? haloColor(p.ti) : 0;
bool rotate = p.si ? p.si->rotate() : false;
bool limit = false;
for (int i = 0; i < paths.size(); i++) {
PainterPath &path = paths[i];
const QByteArray *lbl = label(ri->key(), path.path->tags);
if (!lbl)
continue;
if (!ri->rule().match(path.path->closed, path.path->tags))
continue;
bool limit = (ri->key() == ID_ELE || ri->key() == ID_REF);
if (limit && set.contains(*lbl))
if (p.ti) {
limit = (p.ti->key() == ID_ELE || p.ti->key() == ID_REF);
if (limit && set.contains(*p.lbl))
continue;
}
PathItem *item = new PathItem(path.pp, lbl, _rect, &ri->font(),
&ri->fillColor(), haloColor(ri));
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
set.insert(*lbl);
} else
delete item;
PathItem *item = new PathItem(p.p->pp, p.lbl, img, _rect, font, color,
hColor, rotate);
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
set.insert(*p.lbl);
} else {
delete item;
if (img && p.lbl) {
PathItem *item = new PathItem(p.p->pp, 0, img, _rect, 0, 0, 0,
rotate);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
}
}
@ -200,17 +306,17 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
{
QPainterPath path;
if (curve) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
int size = 0;
for (int i = 0; i < polygon.size(); i++)
size += polygon.at(i).size();
path.reserve(size);
int size = 0;
for (int i = 0; i < polygon.size(); i++)
size += polygon.at(i).size();
path.reserve(size);
#endif // QT 5.13
for (int i = 0; i < polygon.size(); i++) {
const QVector<Coordinates> &subpath = polygon.at(i);
for (int i = 0; i < polygon.size(); i++) {
const QVector<Coordinates> &subpath = polygon.at(i);
if (curve) {
QPointF p1(ll2xy(subpath.first()));
QPointF p2(0, 0);
QPointF p3(0, 0);
@ -223,25 +329,31 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
p1 = p3;
}
path.quadTo(p2, p3);
} else {
path.moveTo(ll2xy(subpath.first()));
for (int j = 1; j < subpath.size(); j++)
path.lineTo(ll2xy(subpath.at(j)));
}
} else {
for (int i = 0; i < polygon.size(); i++) {
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;
}
void RasterTile::pathInstructions(QVector<PainterPath> &paths,
QVector<RasterTile::RenderInstruction> &instructions)
void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions) const
{
QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
QList<const Style::PathRender*> *ri;
for (int i = 0; i < _paths.size(); i++) {
const MapData::Path &path = _paths.at(i);
PainterPath &rp = paths[i];
for (int i = 0; i < paths.size(); i++) {
const MapData::Path &path = paths.at(i);
PainterPath &rp = painterPaths[i];
PathKey key(_zoom, path.closed, path.tags);
rp.path = &path;
@ -259,14 +371,14 @@ void RasterTile::pathInstructions(QVector<PainterPath> &paths,
}
}
void RasterTile::circleInstructions(
QVector<RasterTile::RenderInstruction> &instructions)
void RasterTile::circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions) const
{
QCache<PointKey, QList<const Style::CircleRender *> > cache(8192);
QList<const Style::CircleRender*> *ri;
for (int i = 0; i < _points.size(); i++) {
const MapData::Point &point = _points.at(i);
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
PointKey key(_zoom, point.tags);
if (!(ri = cache.object(key))) {
@ -282,11 +394,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;
pathInstructions(paths, instructions);
circleInstructions(instructions);
pathInstructions(paths, painterPaths, instructions);
circleInstructions(points, instructions);
std::sort(instructions.begin(), instructions.end());
for (int i = 0; i < instructions.size(); i++) {
@ -295,13 +408,18 @@ void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
if (path) {
const Style::PathRender *ri = is.pathRender();
qreal dy = ri->dy(_zoom);
if (!path->pp.elementCount())
path->pp = painterPath(path->path->poly, ri->curve());
painter->setPen(ri->pen(_zoom));
painter->setBrush(ri->brush());
painter->drawPath(path->pp);
if (dy != 0)
painter->drawPath(parallelPath(path->pp, dy));
else
painter->drawPath(path->pp);
} else {
const Style::CircleRender *ri = is.circleRender();
qreal radius = ri->radius(_zoom);
@ -313,28 +431,61 @@ void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
}
}
void RasterTile::fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points) const
{
QPoint ttl(_rect.topLeft());
QRectF pathRect(QPointF(ttl.x() - PATHS_EXTENT, ttl.y() - PATHS_EXTENT),
QPointF(ttl.x() + _rect.width() + PATHS_EXTENT, ttl.y() + _rect.height()
+ PATHS_EXTENT));
QRectF searchRect(QPointF(ttl.x() - SEARCH_EXTENT, ttl.y() - SEARCH_EXTENT),
QPointF(ttl.x() + _rect.width() + SEARCH_EXTENT, ttl.y() + _rect.height()
+ SEARCH_EXTENT));
RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight()));
RectD searchRectD(_transform.img2proj(searchRect.topLeft()),
_transform.img2proj(searchRect.bottomRight()));
_data->paths(searchRectD.toRectC(_proj, 20), 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()
{
QList<MapData::Path> paths;
QList<MapData::Point> points;
fetchData(paths, points);
QList<TextItem*> textItems;
QVector<PainterPath> renderPaths(_paths.size());
QVector<PainterPath> renderPaths(paths.size());
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.translate(-_rect.x(), -_rect.y());
drawPaths(&painter, renderPaths);
drawPaths(&painter, paths, points, renderPaths);
processPointLabels(textItems);
processAreaLabels(textItems, renderPaths);
processLineLabels(textItems, renderPaths);
processPointLabels(points, textItems);
processAreaLabels(renderPaths, textItems);
processLineLabels(renderPaths, textItems);
drawTextItems(&painter, textItems);
//painter.setPen(Qt::red);
//painter.setBrush(Qt::NoBrush);
//painter.drawRect(QRect(_rect.topLeft(), _pixmap.size()));
//painter.setRenderHint(QPainter::Antialiasing, false);
//painter.drawRect(_rect);
qDeleteAll(textItems);

View File

@ -15,11 +15,10 @@ class RasterTile
{
public:
RasterTile(const Projection &proj, const Transform &transform,
const Style *style, int zoom, const QRect &rect, qreal ratio,
const QList<MapData::Path> &paths, const QList<MapData::Point> &points)
: _proj(proj), _transform(transform), _style(style),
_zoom(zoom), _rect(rect), _ratio(ratio), _pixmap(rect.width() * ratio,
rect.height() * ratio), _paths(paths), _points(points), _valid(false) {}
const Style *style, MapData *data, int zoom, const QRect &rect,
qreal ratio) : _proj(proj), _transform(transform), _style(style),
_data(data), _zoom(zoom), _rect(rect), _ratio(ratio),
_pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
int zoom() const {return _zoom;}
QPoint xy() const {return _rect.topLeft();}
@ -36,15 +35,15 @@ private:
const MapData::Path *path;
};
struct PainterPoint {
PainterPoint(const MapData::Point *p, const QByteArray *lbl,
struct PointText {
PointText(const MapData::Point *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: p(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const PainterPoint &other) const
bool operator<(const PointText &other) const
{
if (priority() == other.priority())
return p->id < other.p->id;
@ -59,6 +58,26 @@ private:
const Style::Symbol *si;
};
struct PathText {
PathText(const PainterPath *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: p(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const PathText &other) const
{
return (priority() > other.priority());
}
int priority() const {return si ? si->priority() : ti->priority();}
const PainterPath *p;
const QByteArray *lbl;
const Style::TextRender *ti;
const Style::Symbol *si;
};
class RenderInstruction
{
public:
@ -138,40 +157,44 @@ private:
{
public:
PathItem(const QPainterPath &line, const QByteArray *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextPathItem(line,
label ? new QString(*label) : 0, tileRect, font, color, haloColor) {}
const QImage *img, const QRect &tileRect, const QFont *font,
const QColor *color, const QColor *haloColor, bool rotate)
: TextPathItem(line, label ? new QString(*label) : 0, tileRect, font,
color, haloColor, img, rotate) {}
~PathItem() {delete _text;}
};
friend HASH_T qHash(const RasterTile::PathKey &key);
friend HASH_T qHash(const RasterTile::PointKey &key);
void pathInstructions(QVector<PainterPath> &paths,
QVector<RasterTile::RenderInstruction> &instructions);
void circleInstructions(QVector<RasterTile::RenderInstruction> &instructions);
void fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points) const;
void pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions) const;
void circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions) const;
QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));}
void processPointLabels(QList<TextItem*> &textItems);
void processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
void processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
void processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems) const;
void processAreaLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const;
void processLineLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const;
QPainterPath painterPath(const Polygon &polygon, bool curve) const;
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;
Transform _transform;
const Style *_style;
MapData *_data;
int _zoom;
QRect _rect;
qreal _ratio;
QPixmap _pixmap;
QList<MapData::Path> _paths;
QList<MapData::Point> _points;
bool _valid;
};

View File

@ -17,18 +17,26 @@ static QString resourcePath(const QString &src, const QString &dir)
return dir + "/" + url.toLocalFile();
}
static QImage image(const QString &path, int width, int height, qreal ratio)
static QImage image(const QString &path, int width, int height, int percent,
qreal ratio)
{
QImageReader ir(path, "svg");
if (ir.canRead()) {
QSize s(ir.size());
if (!height && !width) {
height = 20;
width = 20;
} else if (!width) {
width = ir.size().height() / (ir.size().height() / (double)height);
width = s.height() / (s.height() / (double)height);
} else if (!height)
height = ir.size().width() / (ir.size().width() / (double)width);
height = s.width() / (s.width() / (double)width);
if (percent != 100) {
width *= percent / 100.0;
height *= percent / 100.0;
}
ir.setScaledSize(QSize(width * ratio, height * ratio));
QImage img(ir.read());
@ -69,6 +77,42 @@ static QList<QByteArray> valList(const QList<QByteArray> &in)
return out;
}
const Style::Menu::Layer *Style::Menu::findLayer(const QString &id) const
{
for (int i = 0; i < _layers.size(); i++)
if (_layers.at(i).id() == id)
return &_layers.at(i);
qWarning("%s: layer not found", qPrintable(id));
return 0;
}
void Style::Menu::addCats(const Layer *layer, QSet<QString> &cats) const
{
if (!layer)
return;
if (!layer->parent().isNull())
addCats(findLayer(layer->parent()), cats);
for (int i = 0; i < layer->cats().size(); i++)
cats.insert(layer->cats().at(i));
for (int i = 0; i < layer->overlays().size(); i++) {
const Layer *overlay = findLayer(layer->overlays().at(i));
if (overlay && overlay->enabled())
addCats(overlay, cats);
}
}
QSet<QString> Style::Menu::cats() const
{
QSet<QString> c;
addCats(findLayer(_defaultvalue), c);
return c;
}
Style::Rule::Filter::Filter(const MapData &data, const QList<QByteArray> &keys,
const QList<QByteArray> &vals) : _neg(false)
{
@ -139,7 +183,7 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const QXmlStreamAttributes &attr = reader.attributes();
QString file;
QColor fillColor;
int height = 0, width = 0;
int height = 0, width = 0, percent = 100;
bool ok;
ri._area = true;
@ -154,6 +198,13 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
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"))
file = resourcePath(attr.value("src").toString(), dir);
if (attr.hasAttribute("symbol-height")) {
@ -170,9 +221,16 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (!file.isNull())
ri._brush = QBrush(image(file, width, height, ratio));
ri._brush = QBrush(image(file, width, height, percent, ratio));
else if (fillColor.isValid())
ri._brush = QBrush(fillColor);
@ -188,6 +246,8 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
const QXmlStreamAttributes &attr = reader.attributes();
bool ok;
ri._brush = Qt::NoBrush;
if (attr.hasAttribute("stroke"))
ri._strokeColor = QColor(attr.value("stroke").toString());
if (attr.hasAttribute("stroke-width")) {
@ -226,11 +286,25 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
else if (join == "bevel")
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")) {
QString curve(attr.value("curve").toString());
if (curve == "cubic")
ri._curve = true;
}
if (attr.hasAttribute("dy")) {
ri._dy = attr.value("dy").toDouble(&ok);
if (!ok) {
reader.raiseError("invalid dy value");
return;
}
}
if (ri.rule()._type == Rule::AnyType || ri.rule()._type == Rule::WayType)
_paths.append(ri);
@ -347,6 +421,8 @@ void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule
return;
}
}
if (attr.hasAttribute("symbol-id"))
ri._symbolId = attr.value("symbol-id").toString();
ri._font.setFamily(fontFamily);
ri._font.setPixelSize(fontSize);
@ -362,12 +438,12 @@ void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule
}
void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule)
const Rule &rule, QList<Symbol> &list)
{
Symbol ri(rule);
const QXmlStreamAttributes &attr = reader.attributes();
QString file;
int height = 0, width = 0;
int height = 0, width = 0, percent = 100;
bool ok;
if (attr.hasAttribute("src"))
@ -390,6 +466,13 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (attr.hasAttribute("priority")) {
ri._priority = attr.value("priority").toInt(&ok);
if (!ok) {
@ -397,10 +480,16 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("rotate")) {
if (attr.value("rotate").toString() == "false")
ri._rotate = false;
}
if (attr.hasAttribute("id"))
ri._id = attr.value("id").toString();
ri._img = image(file, width, height, ratio);
ri._img = image(file, width, height, percent, ratio);
_symbols.append(ri);
list.append(ri);
reader.skipCurrentElement();
}
@ -472,42 +561,73 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir,
text(reader, data, r, list);
}
else if (reader.name() == QLatin1String("symbol"))
symbol(reader, dir, ratio, r);
symbol(reader, dir, ratio, r, _symbols);
else if (reader.name() == QLatin1String("lineSymbol"))
symbol(reader, dir, ratio, r, _lineSymbols);
else
reader.skipCurrentElement();
}
}
void Style::cat(QXmlStreamReader &reader, QSet<QString> &cats)
QString Style::cat(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
cats.insert(attr.value("id").toString());
if (!attr.hasAttribute("id")) {
reader.raiseError("Missing id attribute");
return QString();
}
QString id(attr.value("id").toString());
reader.skipCurrentElement();
return id;
}
void Style::layer(QXmlStreamReader &reader, QSet<QString> &cats)
Style::Menu::Layer Style::layer(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
bool enabled = (attr.value("enabled").toString() == "true");
if (!attr.hasAttribute("id")) {
reader.raiseError("Missing id attribute");
return Menu::Layer();
}
Menu::Layer l(attr.value("id").toString(),
attr.value("enabled").toString() == "true");
if (attr.hasAttribute("parent"))
l.setParent(attr.value("parent").toString());
while (reader.readNextStartElement()) {
if (enabled && reader.name() == QLatin1String("cat"))
cat(reader, cats);
if (reader.name() == QLatin1String("cat"))
l.addCat(cat(reader));
else if (reader.name() == QLatin1String("overlay"))
l.addOverlay(cat(reader));
else
reader.skipCurrentElement();
}
return l;
}
void Style::stylemenu(QXmlStreamReader &reader, QSet<QString> &cats)
Style::Menu Style::stylemenu(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
if (!attr.hasAttribute("defaultvalue")) {
reader.raiseError("Missing defaultvalue attribute");
return Menu();
}
Style::Menu menu(attr.value("defaultvalue").toString());
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("layer"))
layer(reader, cats);
menu.addLayer(layer(reader));
else
reader.skipCurrentElement();
}
return menu;
}
void Style::rendertheme(QXmlStreamReader &reader, const QString &dir,
@ -519,9 +639,10 @@ void Style::rendertheme(QXmlStreamReader &reader, const QString &dir,
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("rule"))
rule(reader, dir, data, ratio, cats, r);
else if (reader.name() == QLatin1String("stylemenu"))
stylemenu(reader, cats);
else
else if (reader.name() == QLatin1String("stylemenu")) {
Menu menu(stylemenu(reader));
cats = menu.cats();
} else
reader.skipCurrentElement();
}
}
@ -629,7 +750,7 @@ QList<const Style::Symbol*> Style::pointSymbols(int zoom) const
for (int i = 0; i < _symbols.size(); i++) {
const Symbol &symbol = _symbols.at(i);
const Rule & rule = symbol.rule();
const Rule &rule = symbol.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::NodeType))
list.append(&symbol);
@ -638,6 +759,19 @@ QList<const Style::Symbol*> Style::pointSymbols(int zoom) const
return list;
}
QList<const Style::Symbol*> Style::lineSymbols(int zoom) const
{
QList<const Symbol*> list;
for (int i = 0; i < _lineSymbols.size(); i++) {
const Symbol &symbol = _lineSymbols.at(i);
if (symbol.rule()._zooms.contains(zoom))
list.append(&symbol);
}
return list;
}
QList<const Style::Symbol*> Style::areaSymbols(int zoom) const
{
QList<const Symbol*> list;
@ -656,14 +790,18 @@ QList<const Style::Symbol*> Style::areaSymbols(int zoom) const
QPen Style::PathRender::pen(int zoom) const
{
if (_strokeColor.isValid()) {
qreal width = (zoom >= 12)
qreal width = (_scale > None && zoom >= 12)
? pow(1.5, zoom - 12) * _strokeWidth : _strokeWidth;
QPen p(QBrush(_strokeColor), width, Qt::SolidLine, _strokeCap,
_strokeJoin);
if (!_strokeDasharray.isEmpty()) {
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;
}
p.setDashPattern(pattern);
}
return p;
@ -671,6 +809,11 @@ QPen Style::PathRender::pen(int zoom) const
return Qt::NoPen;
}
qreal Style::PathRender::dy(int zoom) const
{
return (_scale && zoom >= 12) ? pow(1.5, zoom - 12) * _dy : _dy;
}
qreal Style::CircleRender::radius(int zoom) const
{
return (_scale && zoom >= 12) ? pow(1.5, zoom - 12) * _radius : _radius;

View File

@ -136,17 +136,21 @@ public:
public:
PathRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap),
_strokeJoin(Qt::RoundJoin), _area(false), _curve(false) {}
_strokeJoin(Qt::RoundJoin), _area(false), _curve(false),
_scale(Stroke), _dy(0) {}
int zOrder() const {return _zOrder;}
QPen pen(int zoom) const;
const QBrush &brush() const {return _brush;}
bool area() const {return _area;}
bool curve() const {return _curve;}
qreal dy(int zoom) const;
private:
friend class Style;
enum Scale {None, Stroke, All};
int _zOrder;
QColor _strokeColor;
qreal _strokeWidth;
@ -155,6 +159,8 @@ public:
Qt::PenJoinStyle _strokeJoin;
QBrush _brush;
bool _area, _curve;
Scale _scale;
qreal _dy;
};
class CircleRender : public Render
@ -186,6 +192,7 @@ public:
: Render(rule), _priority(0), _fillColor(Qt::black),
_strokeColor(Qt::black), _strokeWidth(0) {}
const QString &symbolId() const {return _symbolId;}
const QFont &font() const {return _font;}
const QColor &fillColor() const {return _fillColor;}
const QColor &strokeColor() const {return _strokeColor;}
@ -196,6 +203,7 @@ public:
private:
friend class Style;
QString _symbolId;
int _priority;
QColor _fillColor, _strokeColor;
qreal _strokeWidth;
@ -206,15 +214,20 @@ public:
class Symbol : public Render
{
public:
Symbol(const Rule &rule) : Render(rule), _priority(0) {}
Symbol(const Rule &rule)
: Render(rule), _priority(0), _rotate(true) {}
const QString &id() const {return _id;}
const QImage &img() const {return _img;}
bool rotate() const {return _rotate;}
int priority() const {return _priority;}
private:
friend class Style;
QString _id;
int _priority;
bool _rotate;
QImage _img;
};
@ -230,19 +243,60 @@ public:
QList<const TextRender*> areaLabels(int zoom) const;
QList<const Symbol*> pointSymbols(int zoom) const;
QList<const Symbol*> areaSymbols(int zoom) const;
QList<const Symbol*> lineSymbols(int zoom) const;
private:
class Menu {
public:
class Layer {
public:
Layer() : _enabled(false) {}
Layer(const QString &id, bool enabled)
: _id(id), _enabled(enabled) {}
const QStringList &cats() const {return _cats;}
const QStringList &overlays() const {return _overlays;}
const QString &id() const {return _id;}
const QString &parent() const {return _parent;}
bool enabled() const {return _enabled;}
void setParent(const QString &parent) {_parent = parent;}
void addCat(const QString &cat) {_cats.append(cat);}
void addOverlay(const QString &overlay) {_overlays.append(overlay);}
private:
QStringList _cats;
QStringList _overlays;
QString _id;
QString _parent;
bool _enabled;
};
Menu() {}
Menu(const QString &defaultValue) : _defaultvalue(defaultValue) {}
void addLayer(const Layer &layer) {_layers.append(layer);}
QSet<QString> cats() const;
private:
const Layer *findLayer(const QString &id) const;
void addCats(const Layer *layer, QSet<QString> &cats) const;
QString _defaultvalue;
QList<Layer> _layers;
};
QList<PathRender> _paths;
QList<CircleRender> _circles;
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
QList<Symbol> _symbols;
QList<Symbol> _symbols, _lineSymbols;
bool loadXml(const QString &path, const MapData &data, qreal ratio);
void rendertheme(QXmlStreamReader &reader, const QString &dir,
const MapData &data, qreal ratio);
void layer(QXmlStreamReader &reader, QSet<QString> &cats);
void stylemenu(QXmlStreamReader &reader, QSet<QString> &cats);
void cat(QXmlStreamReader &reader, QSet<QString> &cats);
Menu::Layer layer(QXmlStreamReader &reader);
Menu stylemenu(QXmlStreamReader &reader);
QString cat(QXmlStreamReader &reader);
void rule(QXmlStreamReader &reader, const QString &dir, const MapData &data,
qreal ratio, const QSet<QString> &cats, const Rule &parent);
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
@ -252,7 +306,7 @@ private:
void text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
QList<QList<TextRender> *> &lists);
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule);
const Rule &rule, QList<Symbol> &list);
};
}

View File

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

View File

@ -2,15 +2,13 @@
#include <QPixmapCache>
#include "common/wgs84.h"
#include "common/util.h"
#include "pcs.h"
#include "rectd.h"
#include "pcs.h"
#include "mapsforgemap.h"
using namespace Mapsforge;
#define TEXT_EXTENT 160
MapsforgeMap::MapsforgeMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _data(fileName), _zoom(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))
painter->drawPixmap(ttl, pm);
else {
QList<MapData::Path> paths;
QList<MapData::Point> points;
/* 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));
tiles.append(RasterTile(_projection, _transform, &_style, &_data,
_zoom, QRect(ttl, QSize(_data.tileSize(), _data.tileSize())),
_tileRatio));
}
}
}

View File

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

View File

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

View File

@ -10,7 +10,7 @@
OnlineMap::OnlineMap(const QString &fileName, const QString &name,
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)
: Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds),
_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),
this);
_tileLoader->setUrl(url);
_tileLoader->setAuthorization(authorization);
_tileLoader->setHeaders(headers);
_tileLoader->setQuadTiles(quadTiles);
connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded);
}

View File

@ -13,7 +13,7 @@ class OnlineMap : public Map
public:
OnlineMap(const QString &fileName, const QString &name, const QString &url,
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);
QString name() const {return _name;}

View File

@ -2,8 +2,9 @@
#include <QPainter>
#include "textpathitem.h"
#define CHAR_RATIO 0.55
#define MAX_TEXT_ANGLE 30
#define PADDING 2
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
#define INTERSECTS intersect
@ -12,6 +13,22 @@
#endif // QT 5.15
static void swap(const QLineF &line, QPointF *p1, QPointF *p2)
{
QPointF lp1(line.p1());
QPointF lp2(line.p2());
if ((lp1.rx() < lp2.rx() && p1->rx() > p2->rx())
|| (lp1.ry() < lp2.ry() && p1->ry() > p2->ry())
|| (lp1.rx() > lp2.rx() && p1->rx() < p2->rx())
|| (lp1.ry() > lp2.ry() && p1->ry() < p2->ry())) {
QPointF tmp(*p2);
*p2 = *p1;
*p1 = tmp;
}
}
static bool intersection(const QLineF &line, const QRectF &rect, QPointF *p)
{
if (line.INTERSECTS(QLineF(rect.topLeft(), rect.topRight()), p)
@ -40,20 +57,26 @@ static bool intersection(const QLineF &line, const QRectF &rect, QPointF *p1,
p = p2;
if (line.INTERSECTS(QLineF(rect.topLeft(), rect.bottomLeft()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
p = p2;
}
if (line.INTERSECTS(QLineF(rect.bottomRight(), rect.bottomLeft()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
p = p2;
}
if (line.INTERSECTS(QLineF(rect.bottomRight(), rect.topRight()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
}
Q_ASSERT(p != p2);
@ -197,6 +220,13 @@ static QList<QLineF> lineString(const QPainterPath &path,
return lines;
}
static bool reverse(const QPainterPath &path)
{
QLineF l(path.elementAt(0), path.elementAt(1));
qreal angle = l.angle();
return (angle > 90 && angle < 270) ? true : false;
}
template<class T>
static QPainterPath textPath(const T &path, qreal textWidth,
qreal charWidth, const QRectF &tileRect)
@ -229,109 +259,129 @@ static QPainterPath textPath(const T &path, qreal textWidth,
: QPainterPath();
}
static bool reverse(const QPainterPath &path)
template<class T>
void TextPathItem::init(const T &line, const QRect &tileRect)
{
QLineF l(path.elementAt(0), path.elementAt(1));
qreal angle = l.angle();
return (angle > 90 && angle < 270) ? true : false;
qreal cw, mw, textWidth;
if (_text && _img) {
cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw + _img->width() + PADDING;
} else if (_text) {
cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw;
} else {
cw = _img->width();
mw = _img->height() / 2.0;
textWidth = _img->width();
}
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path)) {
_path = _path.toReversed();
_reverse = true;
}
QPainterPathStroker s;
s.setWidth(mw * 2);
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
}
TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextItem(label), _font(font), _color(color),
_haloColor(haloColor)
const QColor *haloColor, const QImage *img, bool rotate)
: TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
qreal mw = font->pixelSize() / 2;
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path))
_path = _path.toReversed();
QPainterPathStroker s;
s.setWidth(font->pixelSize());
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
init(line, tileRect);
}
TextPathItem::TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextItem(label), _font(font), _color(color),
_haloColor(haloColor)
const QColor *haloColor, const QImage *img, bool rotate)
: TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
qreal mw = font->pixelSize() / 2;
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path))
_path = _path.toReversed();
QPainterPathStroker s;
s.setWidth(font->pixelSize());
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
init(line, tileRect);
}
void TextPathItem::paint(QPainter *painter) const
{
QFontMetrics fm(*_font);
int textWidth = fm.boundingRect(*_text).width();
if (_img) {
QSizeF s(_img->size() / _img->devicePixelRatioF());
qreal factor = (textWidth) / qMax(_path.length(), (qreal)textWidth);
qreal percent = (1.0 - factor) / 2.0;
painter->save();
painter->translate(QPointF(_path.elementAt(0).x, _path.elementAt(0).y));
painter->rotate(360 - _path.angleAtPercent(0));
if (_reverse && _rotate) {
painter->rotate(180);
painter->translate(-s.width(), 0);
}
painter->drawImage(QPointF(0, -s.height()/2), *_img);
painter->restore();
}
QTransform t = painter->transform();
if (_text) {
QFontMetrics fm(*_font);
int textWidth = fm.boundingRect(*_text).width();
int imgWidth = _img ? _img->width() + PADDING : 0;
qreal imgPercent = imgWidth / _path.length();
qreal factor = textWidth / qMax(_path.length(), (qreal)(textWidth));
qreal percent = ((1.0 - factor) + imgPercent) / 2.0;
QTransform t = painter->transform();
painter->setFont(*_font);
painter->setFont(*_font);
if (_haloColor) {
painter->setPen(*_haloColor);
if (_haloColor) {
painter->setPen(*_haloColor);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
QChar c = _text->at(i);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), c);
painter->drawText(QPoint(1, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent() + 1), c);
painter->drawText(QPoint(1, fm.descent() -1), c);
painter->drawText(QPoint(0, fm.descent() - 1), c);
painter->drawText(QPoint(0, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent()), c);
painter->drawText(QPoint(1, fm.descent()), c);
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
percent = ((1.0 - factor) + imgPercent) / 2.0;
}
painter->setPen(_color ? *_color : Qt::black);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
QChar c = _text->at(i);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), c);
painter->drawText(QPoint(1, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent() + 1), c);
painter->drawText(QPoint(1, fm.descent() -1), c);
painter->drawText(QPoint(0, fm.descent() - 1), c);
painter->drawText(QPoint(0, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent()), c);
painter->drawText(QPoint(1, fm.descent()), c);
painter->drawText(QPoint(0, fm.descent()), _text->at(i));
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
percent = (1.0 - factor) / 2.0;
}
painter->setPen(_color ? *_color : Qt::black);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(0, fm.descent()), _text->at(i));
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
//painter->setBrush(Qt::NoBrush);
//painter->setPen(Qt::red);
//painter->setRenderHint(QPainter::Antialiasing, false);
//painter->drawPath(_shape);
}

View File

@ -1,20 +1,21 @@
#ifndef TEXTPATHITEM_H
#define TEXTPATHITEM_H
#include <QVector>
#include <QPainterPath>
#include "textitem.h"
class QFont;
class QImage;
class QColor;
class TextPathItem : public TextItem
{
public:
TextPathItem() : TextItem(0), _font(0), _color(0) {}
TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor);
const QColor *haloColor, const QImage *img = 0, bool rotate = true);
TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor);
const QColor *haloColor, const QImage *img = 0, bool rotate = true);
bool isValid() const {return !_path.isEmpty();}
@ -23,12 +24,14 @@ public:
void paint(QPainter *painter) const;
private:
template<class T> void init(const T &line, const QRect &tileRect);
const QFont *_font;
const QColor *_color;
const QColor *_haloColor;
QPainterPath _path;
const QColor *_color, *_haloColor;
const QImage *_img;
QRectF _rect;
QPainterPath _shape;
QPainterPath _path, _shape;
bool _rotate, _reverse;
};
#endif // TEXTPATHITEM_H

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <QFont>
#include <QFontMetrics>
#include <QImage>
@ -18,9 +19,9 @@ static void expand(QRectF &rect, int width)
TextPointItem::TextPointItem(const QPoint &point, const QString *text,
const QFont *font, const QImage *img, const QColor *color,
const QColor *haloColor, const QColor *bgColor, int padding)
const QColor *haloColor, const QColor *bgColor, int padding, double rotate)
: TextItem(font ? text : 0), _font(font), _img(img), _color(color),
_haloColor(haloColor), _bgColor(bgColor)
_haloColor(haloColor), _bgColor(bgColor), _rotate(rotate)
{
if (_text) {
QFontMetrics fm(*_font);
@ -58,8 +59,17 @@ void TextPointItem::paint(QPainter *painter) const
{
if (_img && !_img->isNull()) {
QSizeF s(_img->size() / _img->devicePixelRatioF());
painter->drawImage(QPointF(_rect.left(), _rect.center().y()
- s.height()/2), *_img);
if (std::isnan(_rotate))
painter->drawImage(QPointF(_rect.left(), _rect.center().y()
- s.height()/2), *_img);
else {
painter->save();
painter->translate(QPointF(_rect.left() + s.width()/2,
_rect.center().y()));
painter->rotate(_rotate);
painter->drawImage(QPointF(-s.width()/2, -s.height()/2), *_img);
painter->restore();
}
}
if (_text) {
@ -99,6 +109,7 @@ void TextPointItem::paint(QPainter *painter) const
}
//painter->setPen(Qt::red);
//painter.setBrush(Qt::NoBrush);
//painter->setRenderHint(QPainter::Antialiasing, false);
//painter->drawRect(_rect);
}

View File

@ -1,12 +1,8 @@
#ifndef TEXTPOINTITEM_H
#define TEXTPOINTITEM_H
#include <QRect>
#include <QString>
#include <QVector>
#include "textitem.h"
class QPainter;
class QFont;
class QImage;
class QColor;
@ -14,10 +10,9 @@ class QColor;
class TextPointItem : public TextItem
{
public:
TextPointItem() : TextItem(0), _font(0), _img(0) {}
TextPointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QColor *color, const QColor *haloColor,
const QColor *bgColor = 0, int padding = 0);
const QColor *bgColor = 0, int padding = 0, double rotate = NAN);
bool isValid() const {return !_rect.isEmpty();}
@ -31,6 +26,7 @@ private:
const QFont *_font;
const QImage *_img;
const QColor *_color, *_haloColor, *_bgColor;
double _rotate;
QRectF _rect, _textRect;
QPainterPath _shape;
};

View File

@ -88,7 +88,7 @@ void TileLoader::loadTilesAsync(QVector<FetchTile> &list)
}
if (!dl.empty())
_downloader->get(dl, _authorization);
_downloader->get(dl, _headers);
QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load);
future.waitForFinished();
@ -130,7 +130,7 @@ void TileLoader::loadTilesSync(QVector<FetchTile> &list)
if (!dl.empty()) {
QEventLoop wait;
connect(_downloader, &Downloader::finished, &wait, &QEventLoop::quit);
if (_downloader->get(dl, _authorization))
if (_downloader->get(dl, _headers))
wait.exec();
for (int i = 0; i < tl.size(); i++) {

View File

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

View File

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

View File

@ -23,13 +23,13 @@ public:
Setup(const QString &url, const QString &layer, const QString &style,
const QString &format, const QString &crs, const CoordinateSystem &cs,
const QList<KV<QString, QString> > &dimensions,
const Authorization &authorization = Authorization())
const QList<HTTPHeader> &headers)
: _url(url), _layer(layer), _style(style), _format(format),
_crs(crs), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {}
_headers(headers) {}
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 &style() const {return _style;}
const QString &format() const {return _format;}
@ -46,7 +46,7 @@ public:
QString _crs;
CoordinateSystem _cs;
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));
_tileLoader = new TileLoader(tilesDir, this);
_tileLoader->setAuthorization(setup.authorization());
_tileLoader->setHeaders(setup.headers());
connect(_tileLoader, &TileLoader::finished, this, &WMSMap::tilesLoaded);
_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;
dl.append(Download(url.toString(), _path));
_valid = downloader->get(dl, _setup.authorization());
_valid = downloader->get(dl, _setup.headers());
} else {
_ready = true;
_valid = init();

View File

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

View File

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