1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 03:35:53 +01:00

Improved text layout/rendering on IMG maps

This commit is contained in:
Martin Tůma 2019-06-07 20:33:08 +02:00
parent f2d32b30d3
commit 06e1685f85
11 changed files with 144 additions and 85 deletions

View File

@ -179,7 +179,8 @@ HEADERS += src/common/config.h \
src/map/IMG/style.h \
src/map/IMG/netfile.h \
src/GUI/limitedcombobox.h \
src/GUI/pathtickitem.h
src/GUI/pathtickitem.h \
src/map/IMG/textitem.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -309,7 +310,8 @@ SOURCES += src/main.cpp \
src/map/IMG/vectortile.cpp \
src/map/IMG/style.cpp \
src/map/IMG/netfile.cpp \
src/GUI/pathtickitem.cpp
src/GUI/pathtickitem.cpp \
src/map/IMG/textitem.cpp
greaterThan(QT_MAJOR_VERSION, 4) {
HEADERS += src/data/geojsonparser.h

View File

@ -75,10 +75,11 @@ void Style::defaultPolygonStyle()
<< TYPE(0x42) << TYPE(0x43) << TYPE(0x44) << TYPE(0x45) << TYPE(0x46)
<< TYPE(0x47) << TYPE(0x48) << TYPE(0x49) << TYPE(0x4c) << TYPE(0x4d)
<< TYPE(0x4e) << TYPE(0x4f) << TYPE(0x50) << TYPE(0x51) << TYPE(0x52)
<< TYPE(0x14) << TYPE(0x15) << TYPE(0x1e) << TYPE(0x1f) << TYPE(0x04)
<< TYPE(0x05) << TYPE(0x06) << TYPE(0x07) << TYPE(0x08) << TYPE(0x09)
<< TYPE(0x0a) << TYPE(0x0b) << TYPE(0x0c) << TYPE(0x0d) << TYPE(0x0e)
<< TYPE(0x0f) << TYPE(0x10) << TYPE(0x11) << TYPE(0x12) << TYPE(0x13);
<< TYPE(0x14) << TYPE(0x15) << TYPE(0x16) << TYPE(0x1e) << TYPE(0x1f)
<< TYPE(0x04) << TYPE(0x05) << TYPE(0x06) << TYPE(0x07) << TYPE(0x08)
<< TYPE(0x09) << TYPE(0x0a) << TYPE(0x0b) << TYPE(0x0c) << TYPE(0x0d)
<< TYPE(0x0e) << TYPE(0x0f) << TYPE(0x10) << TYPE(0x11) << TYPE(0x12)
<< TYPE(0x13);
}
void Style::defaultLineStyle()
@ -962,6 +963,11 @@ bool Style::isSpot(quint32 type)
return (type == TYPE(0x62) || type == TYPE(0x63));
}
bool Style::isSummit(quint32 type)
{
return (type == 0x6616);
}
Style::POIClass Style::poiClass(quint32 type)
{
if ((type >= 0x2a00 && type < 0x2b00) || type == 0x2c0a || type == 0x2d02)

View File

@ -105,6 +105,7 @@ public:
static bool isContourLine(quint32 type);
static bool isSpot(quint32 type);
static bool isSummit(quint32 type);
static POIClass poiClass(quint32 type);
private:

17
src/map/IMG/textitem.cpp Normal file
View File

@ -0,0 +1,17 @@
#include "textitem.h"
bool TextItem::collides(const QList<TextItem*> &list) const
{
QRectF r1(boundingRect());
for (int i = 0; i < list.size(); i++) {
const TextItem* other = list.at(i);
QRectF r2(other->boundingRect());
if (!(r1.isEmpty() || r2.isEmpty() || !r1.intersects(r2)))
if (other->shape().intersects(shape()))
return true;
}
return false;
}

22
src/map/IMG/textitem.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef TEXTITEM_H
#define TEXTITEM_H
#include <QList>
#include <QRectF>
#include <QPainterPath>
class QPainter;
class TextItem
{
public:
virtual ~TextItem() {}
virtual QPainterPath shape() const = 0;
virtual QRectF boundingRect() const = 0;
virtual void paint(QPainter *painter) const = 0;
bool collides(const QList<TextItem*> &list) const;
};
#endif // TEXTITEM_H

View File

@ -154,23 +154,6 @@ TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
_rect = _shape.boundingRect();
}
bool TextPathItem::collides(const QVector<TextPathItem> &list) const
{
if (_rect.isEmpty())
return false;
for (int i = 0; i < list.size(); i++) {
const TextPathItem &other = list.at(i);
if (other._rect.isEmpty() || !_rect.intersects(other._rect))
continue;
if (other._shape.intersects(_shape))
return true;
}
return false;
}
void TextPathItem::paint(QPainter *painter) const
{
QFontMetrics fm(*_font);

View File

@ -3,9 +3,9 @@
#include <QVector>
#include <QPainterPath>
#include "img.h"
#include "textitem.h"
class TextPathItem
class TextPathItem : public TextItem
{
public:
TextPathItem() : _text(0), _font(0), _color(0) {}
@ -13,7 +13,9 @@ public:
const QRect &tileRect, const QFont *font, const QColor *color);
bool isValid() const {return !_path.isEmpty();}
bool collides(const QVector<TextPathItem> &list) const;
QPainterPath shape() const {return _shape;}
QRectF boundingRect() const {return _rect;}
void paint(QPainter *painter) const;
private:

View File

@ -28,15 +28,7 @@ TextPointItem::TextPointItem(const QPoint &point, const QString *text,
_textRect.moveCenter(point);
_rect = _textRect | iconRect;
}
bool TextPointItem::collides(const QVector<TextPointItem> &list) const
{
for (int i = 0; i < list.size(); i++)
if (list.at(i)._rect.intersects(_rect))
return true;
return false;
_shape.addRect(_rect);
}
void TextPointItem::paint(QPainter *painter) const

View File

@ -4,20 +4,24 @@
#include <QRect>
#include <QString>
#include <QVector>
#include "textitem.h"
class QPainter;
class QFont;
class QImage;
class QColor;
class TextPointItem
class TextPointItem : public TextItem
{
public:
TextPointItem() : _text(0), _font(0), _img(0) {}
TextPointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QColor *color);
bool collides(const QVector<TextPointItem> &list) const;
bool isValid() const {return !_rect.isEmpty();}
QRectF boundingRect() const {return _rect;}
QPainterPath shape() const {return _shape;}
void paint(QPainter *painter) const;
private:
@ -26,6 +30,7 @@ private:
const QImage *_img;
const QColor *_color;
QRect _rect, _textRect;
QPainterPath _shape;
};
#endif // TEXTPOINTITEM_H

View File

@ -24,7 +24,7 @@
#define SMALL_FONT_SIZE 10
#define POI_FONT_SIZE 9
#define LINE_TEXT_MIN_ZOOM 23
#define LINE_TEXT_MIN_ZOOM 22
class RasterTile
{
@ -43,6 +43,12 @@ public:
void load()
{
QList<TextItem*> textItems;
_map->processPolygons(_polygons);
_map->processPoints(_points, textItems);
_map->processLines(_lines, _xy, textItems);
_img.fill(Qt::transparent);
QPainter painter(&_img);
@ -51,8 +57,10 @@ public:
painter.translate(-_xy.x(), -_xy.y());
_map->drawPolygons(&painter, _polygons);
_map->drawLines(&painter, _lines, _xy);
_map->drawPoints(&painter, _points);
_map->drawLines(&painter, _lines);
_map->drawTextItems(&painter, textItems);
qDeleteAll(textItems);
}
private:
@ -189,20 +197,15 @@ Coordinates IMGMap::xy2ll(const QPointF &p)
}
void IMGMap::drawPolygons(QPainter *painter, QList<IMG::Poly> &polygons)
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
{
for (int n = 0; n < _img.style().drawOrder().size(); n++) {
for (int i = 0; i < polygons.size(); i++) {
IMG::Poly &poly = polygons[i];
const IMG::Poly &poly = polygons.at(i);
if (poly.type != _img.style().drawOrder().at(n))
continue;
const Style::Polygon &style = _img.style().polygon(poly.type);
for (int j = 0; j < poly.points.size(); j++) {
QPointF &p = poly.points[j];
p = ll2xy(Coordinates(p.x(), p.y()));
}
painter->setPen(style.pen());
painter->setBrush(style.brush());
painter->drawPolygon(poly.points);
@ -210,19 +213,8 @@ void IMGMap::drawPolygons(QPainter *painter, QList<IMG::Poly> &polygons)
}
}
void IMGMap::drawLines(QPainter *painter, QList<IMG::Poly> &lines,
const QPoint &tile)
void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
{
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()));
}
}
painter->setBrush(Qt::NoBrush);
for (int i = 0; i < lines.size(); i++) {
@ -247,12 +239,42 @@ void IMGMap::drawLines(QPainter *painter, QList<IMG::Poly> &lines,
painter->drawPolyline(poly.points);
}
}
}
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)
{
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()));
}
}
if (_zoom < LINE_TEXT_MIN_ZOOM)
return;
QVector<TextPathItem> items;
for (int i = 0; i < lines.size(); i++) {
IMG::Poly &poly = lines[i];
const Style::Line &style = _img.style().line(poly.type);
@ -279,28 +301,26 @@ void IMGMap::drawLines(QPainter *painter, QList<IMG::Poly> &lines,
const QColor *color = style.textColor().isValid()
? &style.textColor() : 0;
TextPathItem item(poly.points, &poly.label, QRect(tile,
QSize(TILE_SIZE, TILE_SIZE)), font, color);
if (item.isValid() && !item.collides(items))
items.append(item);
TextPathItem *item = new TextPathItem(poly.points, &poly.label,
QRect(tile, QSize(TILE_SIZE, TILE_SIZE)), font, color);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
for (int i = 0; i < items.size(); i++)
items.at(i).paint(painter);
}
void IMGMap::drawPoints(QPainter *painter, QList<IMG::Point> &points)
void IMGMap::processPoints(QList<IMG::Point> &points,
QList<TextItem*> &textItems)
{
qSort(points);
QVector<TextPointItem> items;
for (int i = 0; i < points.size(); i++) {
IMG::Point &point = points[i];
const Style::Point &style = _img.style().point(point.type);
int mz = minPOIZoom(Style::poiClass(point.type));
if (point.poi && _zoom < mz)
const Style::Point &style = _img.style().point(point.type);
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
continue;
const QString *label = point.label.isEmpty() ? 0 : &(point.label);
@ -334,15 +354,19 @@ void IMGMap::drawPoints(QPainter *painter, QList<IMG::Point> &points)
if (Style::isSpot(point.type))
convertUnits(point.label);
if (Style::isSummit(point.type) && !point.label.isEmpty()) {
QStringList list = point.label.split(" ");
convertUnits(list.last());
point.label = list.join(" ");
}
TextPointItem item(ll2xy(point.coordinates).toPoint(), label, font, img,
color);
if (!item.collides(items))
items.append(item);
TextPointItem *item = new TextPointItem(
ll2xy(point.coordinates).toPoint(), label, font, img, color);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
for (int i = 0; i < items.size(); i++)
items.at(i).paint(painter);
}
static void render(RasterTile &tile)

View File

@ -8,6 +8,7 @@
#include "common/range.h"
#include "IMG/img.h"
class TextItem;
class IMGMap : public Map
{
@ -41,10 +42,14 @@ private:
Transform transform(int zoom) const;
void updateTransform();
void drawPolygons(QPainter *painter, QList<IMG::Poly> &polygons);
void drawLines(QPainter *painter, QList<IMG::Poly> &lines,
const QPoint &tile);
void drawPoints(QPainter *painter, QList<IMG::Point> &points);
void drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons);
void drawLines(QPainter *painter, const QList<IMG::Poly> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void processPolygons(QList<IMG::Poly> &polygons);
void processLines(QList<IMG::Poly> &lines, const QPoint &tile,
QList<TextItem*> &textItems);
void processPoints(QList<IMG::Point> &points, QList<TextItem*> &textItems);
QString _fileName;
IMG _img;