2019-05-10 18:56:19 +02:00
|
|
|
#include <QFile>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QPixmapCache>
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
|
|
#include <QtCore>
|
|
|
|
#else // QT_VERSION < 5
|
|
|
|
#include <QtConcurrent>
|
|
|
|
#endif // QT_VERSION < 5
|
|
|
|
#include "common/rectc.h"
|
|
|
|
#include "common/wgs84.h"
|
|
|
|
#include "IMG/textpathitem.h"
|
|
|
|
#include "IMG/textpointitem.h"
|
|
|
|
#include "IMG/bitmapline.h"
|
|
|
|
#include "pcs.h"
|
|
|
|
#include "rectd.h"
|
|
|
|
#include "imgmap.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define TILE_SIZE 256
|
|
|
|
#define TEXT_EXTENT 256
|
2019-06-07 20:33:08 +02:00
|
|
|
#define LINE_TEXT_MIN_ZOOM 22
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
class RasterTile
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RasterTile() : _map(0) {}
|
|
|
|
RasterTile(IMGMap *map, const QPoint &xy, const QString &key)
|
|
|
|
: _map(map), _xy(xy), _key(key),
|
|
|
|
_img(TILE_SIZE, TILE_SIZE, QImage::Format_ARGB32_Premultiplied) {}
|
|
|
|
|
|
|
|
const QString &key() const {return _key;}
|
|
|
|
const QPoint &xy() const {return _xy;}
|
|
|
|
QImage &img() {return _img;}
|
|
|
|
QList<IMG::Poly> &polygons() {return _polygons;}
|
|
|
|
QList<IMG::Poly> &lines() {return _lines;}
|
|
|
|
QList<IMG::Point> &points() {return _points;}
|
|
|
|
|
|
|
|
void load()
|
|
|
|
{
|
2019-06-07 20:33:08 +02:00
|
|
|
QList<TextItem*> textItems;
|
|
|
|
|
|
|
|
_map->processPolygons(_polygons);
|
|
|
|
_map->processPoints(_points, textItems);
|
|
|
|
_map->processLines(_lines, _xy, textItems);
|
|
|
|
|
2019-05-10 18:56:19 +02:00
|
|
|
_img.fill(Qt::transparent);
|
|
|
|
|
|
|
|
QPainter painter(&_img);
|
|
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
painter.translate(-_xy.x(), -_xy.y());
|
|
|
|
|
|
|
|
_map->drawPolygons(&painter, _polygons);
|
2019-06-07 20:33:08 +02:00
|
|
|
_map->drawLines(&painter, _lines);
|
|
|
|
_map->drawTextItems(&painter, textItems);
|
|
|
|
|
|
|
|
qDeleteAll(textItems);
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
IMGMap *_map;
|
|
|
|
QPoint _xy;
|
|
|
|
QString _key;
|
|
|
|
QImage _img;
|
|
|
|
QList<IMG::Poly> _polygons;
|
|
|
|
QList<IMG::Poly> _lines;
|
|
|
|
QList<IMG::Point> _points;
|
|
|
|
};
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
|
|
|
|
static QColor shieldColor(Qt::white);
|
|
|
|
static QColor shieldBgColor1("#dd3e3e");
|
|
|
|
static QColor shieldBgColor2("#379947");
|
|
|
|
static QColor shieldBgColor3("#4a7fc1");
|
|
|
|
|
|
|
|
|
|
|
|
static QString convertUnits(const QString &str)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
int number = str.toInt(&ok);
|
2019-06-30 20:39:22 +02:00
|
|
|
return ok ? QString::number(qRound(number * 0.3048)) : str;
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
|
2019-06-07 09:37:10 +02:00
|
|
|
static int minPOIZoom(Style::POIClass cl)
|
|
|
|
{
|
|
|
|
switch (cl) {
|
|
|
|
case Style::Food:
|
|
|
|
case Style::Shopping:
|
|
|
|
case Style::Services:
|
|
|
|
return 27;
|
|
|
|
case Style::Accommodation:
|
|
|
|
case Style::Recreation:
|
|
|
|
return 25;
|
|
|
|
case Style::ManmadePlaces:
|
|
|
|
case Style::NaturePlaces:
|
|
|
|
case Style::Transport:
|
|
|
|
case Style::Community:
|
|
|
|
case Style::Elementary:
|
|
|
|
return 23;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-29 10:27:12 +02:00
|
|
|
static QFont font(int pixelSize)
|
|
|
|
{
|
|
|
|
QFont f;
|
|
|
|
f.setPixelSize(pixelSize);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2019-06-28 07:43:16 +02:00
|
|
|
/* The fonts must be initialized on first usage (after the QGuiApplication
|
|
|
|
instance is created) */
|
|
|
|
#define FONT(name, size) \
|
|
|
|
static const QFont *name() \
|
|
|
|
{ \
|
2019-06-29 10:27:12 +02:00
|
|
|
static QFont f = font(size); \
|
2019-06-28 07:43:16 +02:00
|
|
|
return &f; \
|
|
|
|
}
|
|
|
|
|
2019-07-02 08:52:26 +02:00
|
|
|
FONT(largeFont, 14)
|
|
|
|
FONT(normalFont, 12)
|
|
|
|
FONT(smallFont, 10)
|
|
|
|
FONT(poiFont, 9)
|
2019-06-28 07:43:16 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
static const QColor *shieldBgColor(Label::Shield::Type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Label::Shield::USInterstate:
|
|
|
|
case Label::Shield::Hbox:
|
|
|
|
return &shieldBgColor1;
|
|
|
|
case Label::Shield::USShield:
|
|
|
|
case Label::Shield::Box:
|
|
|
|
return &shieldBgColor2;
|
|
|
|
case Label::Shield::USRound:
|
|
|
|
case Label::Shield::Oval:
|
|
|
|
return &shieldBgColor3;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int minShieldZoom(Label::Shield::Type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Label::Shield::USInterstate:
|
|
|
|
case Label::Shield::Hbox:
|
|
|
|
return 18;
|
|
|
|
case Label::Shield::USShield:
|
|
|
|
case Label::Shield::Box:
|
|
|
|
return 19;
|
|
|
|
case Label::Shield::USRound:
|
|
|
|
case Label::Shield::Oval:
|
|
|
|
return 20;
|
|
|
|
default:
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-28 07:43:16 +02:00
|
|
|
|
2019-05-10 18:56:19 +02:00
|
|
|
IMGMap::IMGMap(const QString &fileName, QObject *parent)
|
2019-07-04 09:05:30 +02:00
|
|
|
: Map(parent), _img(fileName), _projection(PCS::pcs(3857)), _valid(false)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
|
|
|
if (!_img.isValid()) {
|
|
|
|
_errorString = _img.errorString();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-04 09:05:30 +02:00
|
|
|
_zooms = Range(12, 28);
|
2019-05-10 18:56:19 +02:00
|
|
|
_zoom = _zooms.min();
|
|
|
|
|
|
|
|
updateTransform();
|
|
|
|
|
|
|
|
_valid = true;
|
|
|
|
}
|
|
|
|
|
2019-07-04 18:18:03 +02:00
|
|
|
void IMGMap::load()
|
|
|
|
{
|
|
|
|
_img.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMGMap::unload()
|
|
|
|
{
|
|
|
|
_img.clear();
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:56:19 +02:00
|
|
|
QRectF IMGMap::bounds()
|
|
|
|
{
|
|
|
|
RectD prect(_img.bounds(), _projection);
|
|
|
|
return QRectF(_transform.proj2img(prect.topLeft()),
|
|
|
|
_transform.proj2img(prect.bottomRight()));
|
|
|
|
}
|
|
|
|
|
|
|
|
int IMGMap::zoomFit(const QSize &size, const RectC &rect)
|
|
|
|
{
|
|
|
|
if (rect.isValid()) {
|
2019-05-29 18:27:11 +02:00
|
|
|
RectD pr(rect, _projection, 10);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
_zoom = _zooms.min();
|
2019-05-29 18:27:11 +02:00
|
|
|
for (int i = _zooms.min() + 1; i <= _zooms.max(); i++) {
|
|
|
|
Transform t(transform(i));
|
|
|
|
QRectF r(t.proj2img(pr.topLeft()), t.proj2img(pr.bottomRight()));
|
|
|
|
if (size.width() < r.width() || size.height() < r.height())
|
2019-05-10 18:56:19 +02:00
|
|
|
break;
|
|
|
|
_zoom = i;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
_zoom = _zooms.max();
|
|
|
|
|
|
|
|
updateTransform();
|
|
|
|
|
|
|
|
return _zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IMGMap::zoomIn()
|
|
|
|
{
|
|
|
|
_zoom = qMin(_zoom + 1, _zooms.max());
|
|
|
|
updateTransform();
|
|
|
|
return _zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IMGMap::zoomOut()
|
|
|
|
{
|
|
|
|
_zoom = qMax(_zoom - 1, _zooms.min());
|
|
|
|
updateTransform();
|
|
|
|
return _zoom;
|
|
|
|
}
|
|
|
|
|
2019-05-21 17:44:47 +02:00
|
|
|
void IMGMap::setZoom(int zoom)
|
|
|
|
{
|
|
|
|
_zoom = zoom;
|
|
|
|
updateTransform();
|
|
|
|
}
|
|
|
|
|
2019-05-29 18:27:11 +02:00
|
|
|
Transform IMGMap::transform(int zoom) const
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
2019-05-29 18:27:11 +02:00
|
|
|
double scale = (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom);
|
2019-05-10 18:56:19 +02:00
|
|
|
PointD topLeft(_projection.ll2xy(_img.bounds().topLeft()));
|
2019-05-29 18:27:11 +02:00
|
|
|
return Transform(ReferencePoint(PointD(0, 0), topLeft),
|
2019-05-10 18:56:19 +02:00
|
|
|
PointD(scale, scale));
|
|
|
|
}
|
|
|
|
|
2019-05-29 18:27:11 +02:00
|
|
|
void IMGMap::updateTransform()
|
|
|
|
{
|
|
|
|
_transform = transform(_zoom);
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:56:19 +02:00
|
|
|
QPointF IMGMap::ll2xy(const Coordinates &c)
|
|
|
|
{
|
|
|
|
return _transform.proj2img(_projection.ll2xy(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
Coordinates IMGMap::xy2ll(const QPointF &p)
|
|
|
|
{
|
|
|
|
return _projection.xy2ll(_transform.img2proj(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
2019-07-04 18:18:03 +02:00
|
|
|
for (int n = 0; n < _img.style()->drawOrder().size(); n++) {
|
2019-05-10 18:56:19 +02:00
|
|
|
for (int i = 0; i < polygons.size(); i++) {
|
2019-06-07 20:33:08 +02:00
|
|
|
const IMG::Poly &poly = polygons.at(i);
|
2019-07-04 18:18:03 +02:00
|
|
|
if (poly.type != _img.style()->drawOrder().at(n))
|
2019-05-10 18:56:19 +02:00
|
|
|
continue;
|
2019-07-04 18:18:03 +02:00
|
|
|
const Style::Polygon &style = _img.style()->polygon(poly.type);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
painter->setPen(style.pen());
|
|
|
|
painter->setBrush(style.brush());
|
|
|
|
painter->drawPolygon(poly.points);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
|
|
|
painter->setBrush(Qt::NoBrush);
|
|
|
|
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
const IMG::Poly &poly = lines.at(i);
|
2019-07-04 18:18:03 +02:00
|
|
|
const Style::Line &style = _img.style()->line(poly.type);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
if (style.background() == Qt::NoPen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
painter->setPen(style.background());
|
|
|
|
painter->drawPolyline(poly.points);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
const IMG::Poly &poly = lines.at(i);
|
2019-07-04 18:18:03 +02:00
|
|
|
const Style::Line &style = _img.style()->line(poly.type);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
|
|
|
if (!style.img().isNull())
|
|
|
|
BitmapLine::draw(painter, poly.points, style.img());
|
|
|
|
else if (style.foreground() != Qt::NoPen) {
|
|
|
|
painter->setPen(style.foreground());
|
|
|
|
painter->drawPolyline(poly.points);
|
|
|
|
}
|
|
|
|
}
|
2019-06-07 20:33:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMGMap::drawTextItems(QPainter *painter, const QList<TextItem*> &textItems)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < textItems.size(); i++)
|
|
|
|
textItems.at(i)->paint(painter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IMGMap::processPolygons(QList<IMG::Poly> &polygons)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < polygons.size(); i++) {
|
|
|
|
IMG::Poly &poly = polygons[i];
|
|
|
|
for (int j = 0; j < poly.points.size(); j++) {
|
|
|
|
QPointF &p = poly.points[j];
|
|
|
|
p = ll2xy(Coordinates(p.x(), p.y()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMGMap::processLines(QList<IMG::Poly> &lines, const QPoint &tile,
|
|
|
|
QList<TextItem*> &textItems)
|
|
|
|
{
|
2019-06-30 20:39:22 +02:00
|
|
|
QRect tileRect(tile, QSize(TILE_SIZE, TILE_SIZE));
|
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
qStableSort(lines);
|
|
|
|
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
IMG::Poly &poly = lines[i];
|
|
|
|
for (int j = 0; j < poly.points.size(); j++) {
|
|
|
|
QPointF &p = poly.points[j];
|
|
|
|
p = ll2xy(Coordinates(p.x(), p.y()));
|
|
|
|
}
|
|
|
|
}
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
if (_zoom >= LINE_TEXT_MIN_ZOOM) {
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
IMG::Poly &poly = lines[i];
|
2019-07-04 18:18:03 +02:00
|
|
|
const Style::Line &style = _img.style()->line(poly.type);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
if (style.img().isNull() && style.foreground() == Qt::NoPen)
|
|
|
|
continue;
|
|
|
|
if (poly.label.text().isEmpty()
|
|
|
|
|| style.textFontSize() == Style::None)
|
|
|
|
continue;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
if (Style::isContourLine(poly.type))
|
|
|
|
poly.label.setText(convertUnits(poly.label.text()));
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
const QFont *font;
|
|
|
|
switch (style.textFontSize()) {
|
|
|
|
case Style::Large:
|
|
|
|
font = largeFont();
|
|
|
|
break;
|
|
|
|
case Style::Small:
|
|
|
|
font = smallFont();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
font = normalFont();
|
|
|
|
}
|
|
|
|
const QColor *color = style.textColor().isValid()
|
|
|
|
? &style.textColor() : 0;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
TextPathItem *item = new TextPathItem(poly.points,
|
|
|
|
&poly.label.text(), tileRect, font, color);
|
|
|
|
if (item->isValid() && !item->collides(textItems))
|
|
|
|
textItems.append(item);
|
|
|
|
else
|
|
|
|
delete item;
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
2019-06-30 20:39:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int type = 1; type < 7; type++) {
|
|
|
|
if (minShieldZoom((Label::Shield::Type)type) > _zoom)
|
|
|
|
continue;
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
QSet<Label::Shield> shields;
|
|
|
|
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
const IMG::Poly &poly = lines.at(i);
|
|
|
|
const Label::Shield &shield = poly.label.shield();
|
|
|
|
if (shield.type() != type || !Style::isMajorRoad(poly.type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (poly.label.shield().isValid() && !shields.contains(shield)) {
|
|
|
|
bool valid = false;
|
|
|
|
int idx = poly.points.size()/2, inc = 0, sign = 1;
|
|
|
|
|
|
|
|
TextPointItem *item = new TextPointItem(
|
2019-06-30 23:09:09 +02:00
|
|
|
poly.points.at(idx).toPoint(), &shield.text(), smallFont(),
|
2019-06-30 20:39:22 +02:00
|
|
|
0, &shieldColor, shieldBgColor(shield.type()));
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (!item->collides(textItems)
|
|
|
|
&& tileRect.contains(item->boundingRect().toRect())) {
|
|
|
|
valid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
inc++;
|
|
|
|
sign = (sign < 0) ? 1 : -1;
|
|
|
|
idx += inc * sign;
|
|
|
|
|
|
|
|
if (!(idx >= 0 && idx < poly.points.size()))
|
|
|
|
break;
|
|
|
|
|
|
|
|
item->setPos(poly.points.at(idx).toPoint());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valid) {
|
|
|
|
textItems.append(item);
|
|
|
|
shields.insert(shield);
|
|
|
|
} else
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
}
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
void IMGMap::processPoints(QList<IMG::Point> &points,
|
|
|
|
QList<TextItem*> &textItems)
|
2019-05-10 18:56:19 +02:00
|
|
|
{
|
|
|
|
qSort(points);
|
|
|
|
|
|
|
|
for (int i = 0; i < points.size(); i++) {
|
2019-05-12 15:43:46 +02:00
|
|
|
IMG::Point &point = points[i];
|
2019-06-07 20:33:08 +02:00
|
|
|
|
2019-07-04 18:18:03 +02:00
|
|
|
const Style::Point &style = _img.style()->point(point.type);
|
2019-05-10 18:56:19 +02:00
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
|
2019-05-10 18:56:19 +02:00
|
|
|
continue;
|
|
|
|
|
2019-06-30 20:39:22 +02:00
|
|
|
const QString *label = point.label.text().isEmpty()
|
|
|
|
? 0 : &(point.label.text());
|
2019-05-10 18:56:19 +02:00
|
|
|
const QImage *img = style.img().isNull() ? 0 : &style.img();
|
|
|
|
const QFont *font = 0;
|
2019-06-07 09:37:10 +02:00
|
|
|
if (point.poi) {
|
|
|
|
if (style.textFontSize() == Style::None)
|
|
|
|
label = 0;
|
|
|
|
else
|
2019-06-28 07:43:16 +02:00
|
|
|
font = poiFont();
|
2019-06-07 09:37:10 +02:00
|
|
|
} else {
|
2019-05-10 18:56:19 +02:00
|
|
|
switch (style.textFontSize()) {
|
|
|
|
case Style::None:
|
|
|
|
label = 0;
|
|
|
|
break;
|
|
|
|
case Style::Normal:
|
2019-06-28 07:43:16 +02:00
|
|
|
font = normalFont();
|
2019-05-10 18:56:19 +02:00
|
|
|
break;
|
|
|
|
case Style::Small:
|
2019-06-28 07:43:16 +02:00
|
|
|
font = smallFont();
|
2019-05-10 18:56:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
2019-06-28 07:43:16 +02:00
|
|
|
font = largeFont();
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
const QColor *color = style.textColor().isValid()
|
|
|
|
? &style.textColor() : 0;
|
|
|
|
|
|
|
|
if (!label && !img)
|
|
|
|
continue;
|
|
|
|
|
2019-05-12 15:43:46 +02:00
|
|
|
if (Style::isSpot(point.type))
|
2019-06-30 20:39:22 +02:00
|
|
|
point.label.setText(convertUnits(point.label.text()));
|
|
|
|
if (Style::isSummit(point.type) && !point.label.text().isEmpty()) {
|
|
|
|
QStringList list = point.label.text().split(" ");
|
|
|
|
list.last() = convertUnits(list.last());
|
2019-06-07 20:33:08 +02:00
|
|
|
point.label = list.join(" ");
|
|
|
|
}
|
2019-05-12 15:43:46 +02:00
|
|
|
|
2019-06-07 20:33:08 +02:00
|
|
|
TextPointItem *item = new TextPointItem(
|
|
|
|
ll2xy(point.coordinates).toPoint(), label, font, img, color);
|
|
|
|
if (item->isValid() && !item->collides(textItems))
|
|
|
|
textItems.append(item);
|
|
|
|
else
|
|
|
|
delete item;
|
2019-05-10 18:56:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void render(RasterTile &tile)
|
|
|
|
{
|
|
|
|
tile.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
|
|
|
{
|
|
|
|
Q_UNUSED(flags);
|
|
|
|
|
|
|
|
QPointF tl(floor(rect.left() / TILE_SIZE)
|
|
|
|
* TILE_SIZE, floor(rect.top() / TILE_SIZE) * TILE_SIZE);
|
|
|
|
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
|
|
|
int width = ceil(s.width() / TILE_SIZE);
|
|
|
|
int height = ceil(s.height() / TILE_SIZE);
|
|
|
|
|
|
|
|
QList<RasterTile> tiles;
|
|
|
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
for (int j = 0; j < height; j++) {
|
|
|
|
QPixmap pm;
|
|
|
|
QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE);
|
2019-07-04 09:05:30 +02:00
|
|
|
QString key = _img.fileName() + "-" + QString::number(_zoom) + "_"
|
2019-05-10 18:56:19 +02:00
|
|
|
+ QString::number(ttl.x()) + "_" + QString::number(ttl.y());
|
|
|
|
if (QPixmapCache::find(key, pm))
|
|
|
|
painter->drawPixmap(ttl, pm);
|
|
|
|
else {
|
|
|
|
tiles.append(RasterTile(this, ttl, key));
|
|
|
|
RasterTile &tile = tiles.last();
|
|
|
|
|
|
|
|
RectD polyRect(_transform.img2proj(ttl), _transform.img2proj(
|
|
|
|
QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE)));
|
|
|
|
_img.objects(polyRect.toRectC(_projection, 4), _zoom,
|
|
|
|
&(tile.polygons()), &(tile.lines()), 0);
|
|
|
|
RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT,
|
|
|
|
ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x()
|
|
|
|
+ TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT)));
|
|
|
|
_img.objects(pointRect.toRectC(_projection, 4), _zoom,
|
|
|
|
0, 0, &(tile.points()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QFuture<void> future = QtConcurrent::map(tiles, render);
|
|
|
|
future.waitForFinished();
|
|
|
|
|
|
|
|
for (int i = 0; i < tiles.size(); i++) {
|
|
|
|
RasterTile &mt = tiles[i];
|
|
|
|
QPixmap pm(QPixmap::fromImage(mt.img()));
|
|
|
|
if (pm.isNull())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QPixmapCache::insert(mt.key(), pm);
|
|
|
|
|
|
|
|
painter->drawPixmap(mt.xy(), pm);
|
|
|
|
}
|
|
|
|
}
|
2019-05-14 23:01:24 +02:00
|
|
|
|
|
|
|
void IMGMap::setProjection(const Projection &projection)
|
|
|
|
{
|
|
|
|
_projection = projection;
|
|
|
|
updateTransform();
|
|
|
|
QPixmapCache::clear();
|
|
|
|
}
|