mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 11:45:53 +01:00
Improved text layout/rendering on IMG maps
This commit is contained in:
parent
f2d32b30d3
commit
06e1685f85
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
17
src/map/IMG/textitem.cpp
Normal 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
22
src/map/IMG/textitem.h
Normal 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
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user