mirror of
https://github.com/tumic0/QtPBFImagePlugin.git
synced 2024-11-27 21:24:48 +01:00
Improved text layout handling
This commit is contained in:
parent
085a90e0e5
commit
8567ef44d1
@ -278,8 +278,7 @@ bool Style::Layer::Paint::antialias(Layer::Type type, int zoom) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Style::Layer::Layout::Layout(const QJsonObject &json)
|
Style::Layer::Layout::Layout(const QJsonObject &json)
|
||||||
: _lineCap(Qt::FlatCap), _lineJoin(Qt::MiterJoin), _font("Open Sans"),
|
: _lineCap(Qt::FlatCap), _lineJoin(Qt::MiterJoin), _font("Open Sans")
|
||||||
_viewportAlignment(false)
|
|
||||||
{
|
{
|
||||||
// line
|
// line
|
||||||
_lineCap = FunctionS(json["line-cap"], "butt");
|
_lineCap = FunctionS(json["line-cap"], "butt");
|
||||||
@ -292,18 +291,17 @@ Style::Layer::Layout::Layout(const QJsonObject &json)
|
|||||||
_textMaxWidth = FunctionF(json["text-max-width"], 10);
|
_textMaxWidth = FunctionF(json["text-max-width"], 10);
|
||||||
_textMaxAngle = FunctionF(json["text-max-angle"], 45);
|
_textMaxAngle = FunctionF(json["text-max-angle"], 45);
|
||||||
_textTransform = FunctionS(json["text-transform"], "none");
|
_textTransform = FunctionS(json["text-transform"], "none");
|
||||||
|
_textRotationAlignment = FunctionS(json["text-rotation-alignment"]);
|
||||||
|
_textAnchor = FunctionS(json["text-anchor"]);
|
||||||
|
|
||||||
if (json.contains("text-font") && json["text-font"].isArray())
|
if (json.contains("text-font") && json["text-font"].isArray())
|
||||||
_font = Font::fromJsonArray(json["text-font"].toArray());
|
_font = Font::fromJsonArray(json["text-font"].toArray());
|
||||||
if (json.contains("text-rotation-alignment")
|
|
||||||
&& json["text-rotation-alignment"].isString())
|
|
||||||
if (json["text-rotation-alignment"].toString() == "viewport")
|
|
||||||
_viewportAlignment = true;
|
|
||||||
|
|
||||||
_textAnchor = FunctionS(json["text-anchor"]);
|
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
_icon = Template(FunctionS(json["icon-image"]));
|
_icon = Template(FunctionS(json["icon-image"]));
|
||||||
|
|
||||||
|
// symbol
|
||||||
|
_symbolPlacement = FunctionS(json["symbol-placement"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QFont Style::Layer::Layout::font(int zoom) const
|
QFont Style::Layer::Layout::font(int zoom) const
|
||||||
@ -367,6 +365,31 @@ Qt::PenJoinStyle Style::Layer::Layout::lineJoin(int zoom) const
|
|||||||
return Qt::MiterJoin;
|
return Qt::MiterJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text::SymbolPlacement Style::Layer::Layout::symbolPlacement(int zoom) const
|
||||||
|
{
|
||||||
|
QString placement(_symbolPlacement.value(zoom));
|
||||||
|
|
||||||
|
if (placement == "line")
|
||||||
|
return Text::Line;
|
||||||
|
else if (placement == "line-center")
|
||||||
|
return Text::LineCenter;
|
||||||
|
else
|
||||||
|
return Text::Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Text::RotationAlignment Style::Layer::Layout::textRotationAlignment(int zoom)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
QString alignment(_textRotationAlignment.value(zoom));
|
||||||
|
|
||||||
|
if (alignment == "map")
|
||||||
|
return Text::Map;
|
||||||
|
else if (alignment == "viewport")
|
||||||
|
return Text::Viewport;
|
||||||
|
else
|
||||||
|
return Text::Auto;
|
||||||
|
}
|
||||||
|
|
||||||
Style::Layer::Layer(const QJsonObject &json)
|
Style::Layer::Layer(const QJsonObject &json)
|
||||||
: _type(Unknown), _minZoom(-1), _maxZoom(-1)
|
: _type(Unknown), _minZoom(-1), _maxZoom(-1)
|
||||||
{
|
{
|
||||||
@ -437,6 +460,8 @@ void Style::Layer::setTextProperties(Tile &tile) const
|
|||||||
tile.text().setAnchor(_layout.textAnchor(tile.zoom()));
|
tile.text().setAnchor(_layout.textAnchor(tile.zoom()));
|
||||||
tile.text().setPen(_paint.pen(_type, tile.zoom()));
|
tile.text().setPen(_paint.pen(_type, tile.zoom()));
|
||||||
tile.text().setFont(_layout.font(tile.zoom()));
|
tile.text().setFont(_layout.font(tile.zoom()));
|
||||||
|
tile.text().setSymbolPlacement(_layout.symbolPlacement(tile.zoom()));
|
||||||
|
tile.text().setRotationAlignment(_layout.textRotationAlignment(tile.zoom()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,
|
void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,
|
||||||
@ -447,13 +472,7 @@ void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QString icon = _layout.icon(tile.zoom(), tags);
|
QString icon = _layout.icon(tile.zoom(), tags);
|
||||||
|
tile.text().addLabel(text, sprites.icon(icon), path);
|
||||||
if (_layout.viewportAlignment())
|
|
||||||
tile.text().addLabel(text, path.elementAt(0), false, sprites.icon(icon));
|
|
||||||
else if (path.elementCount() == 1 && path.elementAt(0).isMoveTo())
|
|
||||||
tile.text().addLabel(text, path.elementAt(0), true, sprites.icon(icon));
|
|
||||||
else
|
|
||||||
tile.text().addLabel(text, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Style::load(const QString &fileName)
|
bool Style::load(const QString &fileName)
|
||||||
|
@ -94,7 +94,7 @@ private:
|
|||||||
class Layout {
|
class Layout {
|
||||||
public:
|
public:
|
||||||
Layout() : _textSize(16), _textMaxWidth(10), _textMaxAngle(45),
|
Layout() : _textSize(16), _textMaxWidth(10), _textMaxAngle(45),
|
||||||
_font("Open Sans"), _viewportAlignment(false) {}
|
_font("Open Sans") {}
|
||||||
Layout(const QJsonObject &json);
|
Layout(const QJsonObject &json);
|
||||||
|
|
||||||
qreal maxTextWidth(int zoom) const
|
qreal maxTextWidth(int zoom) const
|
||||||
@ -109,7 +109,8 @@ private:
|
|||||||
Qt::PenCapStyle lineCap(int zoom) const;
|
Qt::PenCapStyle lineCap(int zoom) const;
|
||||||
Qt::PenJoinStyle lineJoin(int zoom) const;
|
Qt::PenJoinStyle lineJoin(int zoom) const;
|
||||||
Text::Anchor textAnchor(int zoom) const;
|
Text::Anchor textAnchor(int zoom) const;
|
||||||
bool viewportAlignment() const {return _viewportAlignment;}
|
Text::SymbolPlacement symbolPlacement(int zoom) const;
|
||||||
|
Text::RotationAlignment textRotationAlignment(int zoom) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QFont::Capitalization textTransform(int zoom) const;
|
QFont::Capitalization textTransform(int zoom) const;
|
||||||
@ -123,8 +124,9 @@ private:
|
|||||||
FunctionS _lineJoin;
|
FunctionS _lineJoin;
|
||||||
FunctionS _textAnchor;
|
FunctionS _textAnchor;
|
||||||
FunctionS _textTransform;
|
FunctionS _textTransform;
|
||||||
|
FunctionS _symbolPlacement;
|
||||||
|
FunctionS _textRotationAlignment;
|
||||||
QFont _font;
|
QFont _font;
|
||||||
bool _viewportAlignment;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Paint {
|
class Paint {
|
||||||
|
69
src/text.cpp
69
src/text.cpp
@ -1,4 +1,4 @@
|
|||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "textpointitem.h"
|
#include "textpointitem.h"
|
||||||
@ -20,15 +20,36 @@ void Text::render(QPainter *painter) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text::addLabel(const QString &text, const QPointF &pos, bool overlap,
|
void Text::addLabel(const QString &text, const QImage &icon,
|
||||||
const QImage &icon)
|
const QPainterPath &path)
|
||||||
{
|
{
|
||||||
TextPointItem *ti = new TextPointItem(text, pos, _font, _maxWidth, _anchor,
|
TextItem *ti;
|
||||||
icon);
|
|
||||||
if (!overlap && !_sceneRect.contains(ti->boundingRect())) {
|
switch (_placement) {
|
||||||
delete ti;
|
case Line:
|
||||||
return;
|
if (_alignment == Viewport)
|
||||||
|
ti = new TextPointItem(text, path.elementAt(0), _font,
|
||||||
|
_maxWidth, _anchor, icon);
|
||||||
|
else
|
||||||
|
ti = new TextPathItem(text, path, _font, _maxAngle, _sceneRect);
|
||||||
|
if (!_sceneRect.contains(ti->boundingRect()))
|
||||||
|
ti->setVisible(false);
|
||||||
|
break;
|
||||||
|
case LineCenter:
|
||||||
|
ti = new TextPointItem(text, path.pointAtPercent(0.5), _font,
|
||||||
|
_maxWidth, _anchor, icon);
|
||||||
|
if (!_sceneRect.contains(ti->boundingRect()))
|
||||||
|
ti->setVisible(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ti = new TextPointItem(text, path.elementAt(0), _font, _maxWidth,
|
||||||
|
_anchor, icon);
|
||||||
|
if (_alignment == Viewport
|
||||||
|
&& !_sceneRect.contains(ti->boundingRect()))
|
||||||
|
ti->setVisible(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ti->setPen(_pen);
|
ti->setPen(_pen);
|
||||||
addItem(ti);
|
addItem(ti);
|
||||||
|
|
||||||
@ -37,23 +58,6 @@ void Text::addLabel(const QString &text, const QPointF &pos, bool overlap,
|
|||||||
ci[i]->setVisible(false);
|
ci[i]->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text::addLabel(const QString &text, const QPainterPath &path)
|
|
||||||
{
|
|
||||||
TextPathItem *ti = new TextPathItem(text, path, _font, _maxAngle,
|
|
||||||
_sceneRect);
|
|
||||||
if (!_sceneRect.contains(ti->boundingRect())) {
|
|
||||||
delete ti;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ti->setPen(_pen);
|
|
||||||
|
|
||||||
addItem(ti);
|
|
||||||
|
|
||||||
QList<TextItem*> ci = collidingItems(ti);
|
|
||||||
for (int i = 0; i < ci.size(); i++)
|
|
||||||
ci[i]->setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<TextItem*> Text::collidingItems(const TextItem *item) const
|
QList<TextItem*> Text::collidingItems(const TextItem *item) const
|
||||||
{
|
{
|
||||||
QList<TextItem*> list;
|
QList<TextItem*> list;
|
||||||
@ -61,7 +65,7 @@ QList<TextItem*> Text::collidingItems(const TextItem *item) const
|
|||||||
if (!item->isVisible())
|
if (!item->isVisible())
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
for (int i = 0; i < _items.size();i ++) {
|
for (int i = 0; i < _items.size(); i++) {
|
||||||
const TextItem *ti = _items.at(i);
|
const TextItem *ti = _items.at(i);
|
||||||
if (ti != item && ti->isVisible() && ti->collidesWithItem(item))
|
if (ti != item && ti->isVisible() && ti->collidesWithItem(item))
|
||||||
list.append(const_cast<TextItem*>(ti));
|
list.append(const_cast<TextItem*>(ti));
|
||||||
@ -69,3 +73,16 @@ QList<TextItem*> Text::collidingItems(const TextItem *item) const
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Text::setSymbolPlacement(SymbolPlacement placement)
|
||||||
|
{
|
||||||
|
_placement = placement;
|
||||||
|
|
||||||
|
if (_placement != Text::Point) {
|
||||||
|
for (int i = 0; i < _items.size(); i++) {
|
||||||
|
TextItem *ti = _items[i];
|
||||||
|
if (!_sceneRect.contains(ti->boundingRect()))
|
||||||
|
ti->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
22
src/text.h
22
src/text.h
@ -22,6 +22,18 @@ public:
|
|||||||
Bottom
|
Bottom
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SymbolPlacement {
|
||||||
|
Point,
|
||||||
|
Line,
|
||||||
|
LineCenter
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RotationAlignment {
|
||||||
|
Map,
|
||||||
|
Viewport,
|
||||||
|
Auto
|
||||||
|
};
|
||||||
|
|
||||||
Text(const QSize &size)
|
Text(const QSize &size)
|
||||||
: _sceneRect(QRectF(QPointF(0, 0), size)) {}
|
: _sceneRect(QRectF(QPointF(0, 0), size)) {}
|
||||||
~Text();
|
~Text();
|
||||||
@ -31,10 +43,12 @@ public:
|
|||||||
void setAnchor(Anchor anchor) {_anchor = anchor;}
|
void setAnchor(Anchor anchor) {_anchor = anchor;}
|
||||||
void setMaxWidth(int width) {_maxWidth = width;}
|
void setMaxWidth(int width) {_maxWidth = width;}
|
||||||
void setMaxAngle(int angle) {_maxAngle = angle;}
|
void setMaxAngle(int angle) {_maxAngle = angle;}
|
||||||
|
void setSymbolPlacement(SymbolPlacement placement);
|
||||||
|
void setRotationAlignment(RotationAlignment alignment)
|
||||||
|
{_alignment = alignment;}
|
||||||
|
|
||||||
void addLabel(const QString &text, const QPointF &pos, bool overlap,
|
void addLabel(const QString &text, const QImage &icon,
|
||||||
const QImage &icon);
|
const QPainterPath &path);
|
||||||
void addLabel(const QString &text, const QPainterPath &path);
|
|
||||||
|
|
||||||
void render(QPainter *painter) const;
|
void render(QPainter *painter) const;
|
||||||
|
|
||||||
@ -48,6 +62,8 @@ private:
|
|||||||
int _maxWidth;
|
int _maxWidth;
|
||||||
int _maxAngle;
|
int _maxAngle;
|
||||||
Anchor _anchor;
|
Anchor _anchor;
|
||||||
|
SymbolPlacement _placement;
|
||||||
|
RotationAlignment _alignment;
|
||||||
QFont _font;
|
QFont _font;
|
||||||
QPen _pen;
|
QPen _pen;
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,10 @@ public:
|
|||||||
virtual ~TextItem() {}
|
virtual ~TextItem() {}
|
||||||
|
|
||||||
const QString &text() const {return _text;}
|
const QString &text() const {return _text;}
|
||||||
|
const QFont &font() const {return _font;}
|
||||||
|
void setFont(const QFont &font) {_font = font;}
|
||||||
|
const QPen &pen() const {return _pen;}
|
||||||
|
void setPen(const QPen &pen) {_pen = pen;}
|
||||||
|
|
||||||
virtual QPainterPath shape() const = 0;
|
virtual QPainterPath shape() const = 0;
|
||||||
virtual QRectF boundingRect() const = 0;
|
virtual QRectF boundingRect() const = 0;
|
||||||
@ -49,6 +53,8 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QString _text;
|
QString _text;
|
||||||
|
QFont _font;
|
||||||
|
QPen _pen;
|
||||||
bool _visible;
|
bool _visible;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ static bool reverse(const QPainterPath &path)
|
|||||||
|
|
||||||
TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
|
TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
|
||||||
const QFont &font, int maxAngle, const QRectF &tileRect)
|
const QFont &font, int maxAngle, const QRectF &tileRect)
|
||||||
: TextItem(text), _font(font)
|
: TextItem(text)
|
||||||
{
|
{
|
||||||
int cw = avgCharWidth(text, font);
|
int cw = avgCharWidth(text, font);
|
||||||
int textWidth = text.size() * cw;
|
int textWidth = text.size() * cw;
|
||||||
@ -146,6 +146,7 @@ TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_path = reverse(tp) ? tp.toReversed() : tp;
|
_path = reverse(tp) ? tp.toReversed() : tp;
|
||||||
|
setFont(font);
|
||||||
|
|
||||||
QPainterPathStroker s;
|
QPainterPathStroker s;
|
||||||
s.setWidth(font.pixelSize());
|
s.setWidth(font.pixelSize());
|
||||||
@ -159,14 +160,14 @@ void TextPathItem::paint(QPainter *painter) const
|
|||||||
//painter->setPen(Qt::red);
|
//painter->setPen(Qt::red);
|
||||||
//painter->drawPath(_shape);
|
//painter->drawPath(_shape);
|
||||||
|
|
||||||
QFontMetrics fm(_font);
|
QFontMetrics fm(font());
|
||||||
int textWidth = fm.width(text());
|
int textWidth = fm.width(text());
|
||||||
|
|
||||||
qreal factor = (textWidth) / qMax(_path.length(), (qreal)textWidth);
|
qreal factor = (textWidth) / qMax(_path.length(), (qreal)textWidth);
|
||||||
qreal percent = (1.0 - factor) / 2.0;
|
qreal percent = (1.0 - factor) / 2.0;
|
||||||
|
|
||||||
painter->setFont(_font);
|
painter->setFont(font());
|
||||||
painter->setPen(_pen);
|
painter->setPen(pen());
|
||||||
|
|
||||||
QTransform t = painter->transform();
|
QTransform t = painter->transform();
|
||||||
|
|
||||||
|
@ -16,14 +16,10 @@ public:
|
|||||||
QRectF boundingRect() const {return _boundingRect;}
|
QRectF boundingRect() const {return _boundingRect;}
|
||||||
void paint(QPainter *painter) const;
|
void paint(QPainter *painter) const;
|
||||||
|
|
||||||
void setPen(const QPen &pen) {_pen = pen;}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPainterPath _path;
|
QPainterPath _path;
|
||||||
QPainterPath _shape;
|
QPainterPath _shape;
|
||||||
QRectF _boundingRect;
|
QRectF _boundingRect;
|
||||||
QFont _font;
|
|
||||||
QPen _pen;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TEXTPATHITEM_H
|
#endif // TEXTPATHITEM_H
|
||||||
|
@ -72,7 +72,7 @@ QRectF TextPointItem::fuzzyBoundingRect(const QString &str,
|
|||||||
QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
||||||
{
|
{
|
||||||
QRectF iconRect = _icon.isNull() ? QRectF() : _icon.rect();
|
QRectF iconRect = _icon.isNull() ? QRectF() : _icon.rect();
|
||||||
QRectF textRect = brf(text(), _font, _maxWidth);
|
QRectF textRect = brf(text(), font(), _maxWidth);
|
||||||
|
|
||||||
switch (_anchor) {
|
switch (_anchor) {
|
||||||
case Text::Center:
|
case Text::Center:
|
||||||
@ -101,9 +101,10 @@ QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
|||||||
|
|
||||||
TextPointItem::TextPointItem(const QString &text, const QPointF &pos,
|
TextPointItem::TextPointItem(const QString &text, const QPointF &pos,
|
||||||
const QFont &font, int maxWidth, Text::Anchor anchor, const QImage &icon)
|
const QFont &font, int maxWidth, Text::Anchor anchor, const QImage &icon)
|
||||||
: TextItem(text), _pos(pos), _font(font), _icon(icon), _maxWidth(maxWidth),
|
: TextItem(text), _pos(pos), _icon(icon), _maxWidth(maxWidth),
|
||||||
_anchor(anchor)
|
_anchor(anchor)
|
||||||
{
|
{
|
||||||
|
setFont(font);
|
||||||
_boundingRect = computeTextRect(fuzzyBoundingRect);
|
_boundingRect = computeTextRect(fuzzyBoundingRect);
|
||||||
|
|
||||||
if (!_icon.isNull()) {
|
if (!_icon.isNull()) {
|
||||||
@ -129,7 +130,7 @@ void TextPointItem::paint(QPainter *painter) const
|
|||||||
} else
|
} else
|
||||||
textRect = computeTextRect(fuzzyBoundingRect);
|
textRect = computeTextRect(fuzzyBoundingRect);
|
||||||
|
|
||||||
painter->setFont(_font);
|
painter->setFont(font());
|
||||||
painter->setPen(_pen);
|
painter->setPen(pen());
|
||||||
painter->drawText(textRect, FLAGS, text());
|
painter->drawText(textRect, FLAGS, text());
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ public:
|
|||||||
QPainterPath shape() const {return _shape;}
|
QPainterPath shape() const {return _shape;}
|
||||||
void paint(QPainter *painter) const;
|
void paint(QPainter *painter) const;
|
||||||
|
|
||||||
void setPen(const QPen &pen) {_pen = pen;}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QRectF (*BoundingRectFunction)(const QString &, const QFont &, int);
|
typedef QRectF (*BoundingRectFunction)(const QString &, const QFont &, int);
|
||||||
|
|
||||||
@ -32,8 +30,6 @@ private:
|
|||||||
QPointF _pos;
|
QPointF _pos;
|
||||||
QPainterPath _shape;
|
QPainterPath _shape;
|
||||||
QRectF _boundingRect;
|
QRectF _boundingRect;
|
||||||
QFont _font;
|
|
||||||
QPen _pen;
|
|
||||||
QImage _icon;
|
QImage _icon;
|
||||||
int _maxWidth;
|
int _maxWidth;
|
||||||
Text::Anchor _anchor;
|
Text::Anchor _anchor;
|
||||||
|
Loading…
Reference in New Issue
Block a user