mirror of
https://github.com/tumic0/QtPBFImagePlugin.git
synced 2024-11-24 03:35:54 +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)
|
||||
: _lineCap(Qt::FlatCap), _lineJoin(Qt::MiterJoin), _font("Open Sans"),
|
||||
_viewportAlignment(false)
|
||||
: _lineCap(Qt::FlatCap), _lineJoin(Qt::MiterJoin), _font("Open Sans")
|
||||
{
|
||||
// line
|
||||
_lineCap = FunctionS(json["line-cap"], "butt");
|
||||
@ -292,18 +291,17 @@ Style::Layer::Layout::Layout(const QJsonObject &json)
|
||||
_textMaxWidth = FunctionF(json["text-max-width"], 10);
|
||||
_textMaxAngle = FunctionF(json["text-max-angle"], 45);
|
||||
_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())
|
||||
_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 = Template(FunctionS(json["icon-image"]));
|
||||
|
||||
// symbol
|
||||
_symbolPlacement = FunctionS(json["symbol-placement"]);
|
||||
}
|
||||
|
||||
QFont Style::Layer::Layout::font(int zoom) const
|
||||
@ -367,6 +365,31 @@ Qt::PenJoinStyle Style::Layer::Layout::lineJoin(int zoom) const
|
||||
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)
|
||||
: _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().setPen(_paint.pen(_type, 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,
|
||||
@ -447,13 +472,7 @@ void Style::Layer::addSymbol(Tile &tile, const QPainterPath &path,
|
||||
return;
|
||||
|
||||
QString icon = _layout.icon(tile.zoom(), tags);
|
||||
|
||||
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);
|
||||
tile.text().addLabel(text, sprites.icon(icon), path);
|
||||
}
|
||||
|
||||
bool Style::load(const QString &fileName)
|
||||
|
@ -94,7 +94,7 @@ private:
|
||||
class Layout {
|
||||
public:
|
||||
Layout() : _textSize(16), _textMaxWidth(10), _textMaxAngle(45),
|
||||
_font("Open Sans"), _viewportAlignment(false) {}
|
||||
_font("Open Sans") {}
|
||||
Layout(const QJsonObject &json);
|
||||
|
||||
qreal maxTextWidth(int zoom) const
|
||||
@ -109,7 +109,8 @@ private:
|
||||
Qt::PenCapStyle lineCap(int zoom) const;
|
||||
Qt::PenJoinStyle lineJoin(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:
|
||||
QFont::Capitalization textTransform(int zoom) const;
|
||||
@ -123,8 +124,9 @@ private:
|
||||
FunctionS _lineJoin;
|
||||
FunctionS _textAnchor;
|
||||
FunctionS _textTransform;
|
||||
FunctionS _symbolPlacement;
|
||||
FunctionS _textRotationAlignment;
|
||||
QFont _font;
|
||||
bool _viewportAlignment;
|
||||
};
|
||||
|
||||
class Paint {
|
||||
|
67
src/text.cpp
67
src/text.cpp
@ -1,4 +1,4 @@
|
||||
#include <QFontMetrics>
|
||||
#include <QFontMetrics>
|
||||
#include <QPainter>
|
||||
#include "text.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,
|
||||
const QImage &icon)
|
||||
void Text::addLabel(const QString &text, const QImage &icon,
|
||||
const QPainterPath &path)
|
||||
{
|
||||
TextPointItem *ti = new TextPointItem(text, pos, _font, _maxWidth, _anchor,
|
||||
icon);
|
||||
if (!overlap && !_sceneRect.contains(ti->boundingRect())) {
|
||||
delete ti;
|
||||
return;
|
||||
TextItem *ti;
|
||||
|
||||
switch (_placement) {
|
||||
case Line:
|
||||
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);
|
||||
addItem(ti);
|
||||
|
||||
@ -37,23 +58,6 @@ void Text::addLabel(const QString &text, const QPointF &pos, bool overlap,
|
||||
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*> list;
|
||||
@ -69,3 +73,16 @@ QList<TextItem*> Text::collidingItems(const TextItem *item) const
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
enum SymbolPlacement {
|
||||
Point,
|
||||
Line,
|
||||
LineCenter
|
||||
};
|
||||
|
||||
enum RotationAlignment {
|
||||
Map,
|
||||
Viewport,
|
||||
Auto
|
||||
};
|
||||
|
||||
Text(const QSize &size)
|
||||
: _sceneRect(QRectF(QPointF(0, 0), size)) {}
|
||||
~Text();
|
||||
@ -31,10 +43,12 @@ public:
|
||||
void setAnchor(Anchor anchor) {_anchor = anchor;}
|
||||
void setMaxWidth(int width) {_maxWidth = width;}
|
||||
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,
|
||||
const QImage &icon);
|
||||
void addLabel(const QString &text, const QPainterPath &path);
|
||||
void addLabel(const QString &text, const QImage &icon,
|
||||
const QPainterPath &path);
|
||||
|
||||
void render(QPainter *painter) const;
|
||||
|
||||
@ -48,6 +62,8 @@ private:
|
||||
int _maxWidth;
|
||||
int _maxAngle;
|
||||
Anchor _anchor;
|
||||
SymbolPlacement _placement;
|
||||
RotationAlignment _alignment;
|
||||
QFont _font;
|
||||
QPen _pen;
|
||||
};
|
||||
|
@ -11,6 +11,10 @@ public:
|
||||
virtual ~TextItem() {}
|
||||
|
||||
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 QRectF boundingRect() const = 0;
|
||||
@ -49,6 +53,8 @@ protected:
|
||||
|
||||
private:
|
||||
QString _text;
|
||||
QFont _font;
|
||||
QPen _pen;
|
||||
bool _visible;
|
||||
};
|
||||
|
||||
|
@ -134,7 +134,7 @@ static bool reverse(const QPainterPath &path)
|
||||
|
||||
TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
|
||||
const QFont &font, int maxAngle, const QRectF &tileRect)
|
||||
: TextItem(text), _font(font)
|
||||
: TextItem(text)
|
||||
{
|
||||
int cw = avgCharWidth(text, font);
|
||||
int textWidth = text.size() * cw;
|
||||
@ -146,6 +146,7 @@ TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
|
||||
return;
|
||||
|
||||
_path = reverse(tp) ? tp.toReversed() : tp;
|
||||
setFont(font);
|
||||
|
||||
QPainterPathStroker s;
|
||||
s.setWidth(font.pixelSize());
|
||||
@ -159,14 +160,14 @@ void TextPathItem::paint(QPainter *painter) const
|
||||
//painter->setPen(Qt::red);
|
||||
//painter->drawPath(_shape);
|
||||
|
||||
QFontMetrics fm(_font);
|
||||
QFontMetrics fm(font());
|
||||
int textWidth = fm.width(text());
|
||||
|
||||
qreal factor = (textWidth) / qMax(_path.length(), (qreal)textWidth);
|
||||
qreal percent = (1.0 - factor) / 2.0;
|
||||
|
||||
painter->setFont(_font);
|
||||
painter->setPen(_pen);
|
||||
painter->setFont(font());
|
||||
painter->setPen(pen());
|
||||
|
||||
QTransform t = painter->transform();
|
||||
|
||||
|
@ -16,14 +16,10 @@ public:
|
||||
QRectF boundingRect() const {return _boundingRect;}
|
||||
void paint(QPainter *painter) const;
|
||||
|
||||
void setPen(const QPen &pen) {_pen = pen;}
|
||||
|
||||
private:
|
||||
QPainterPath _path;
|
||||
QPainterPath _shape;
|
||||
QRectF _boundingRect;
|
||||
QFont _font;
|
||||
QPen _pen;
|
||||
};
|
||||
|
||||
#endif // TEXTPATHITEM_H
|
||||
|
@ -72,7 +72,7 @@ QRectF TextPointItem::fuzzyBoundingRect(const QString &str,
|
||||
QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
||||
{
|
||||
QRectF iconRect = _icon.isNull() ? QRectF() : _icon.rect();
|
||||
QRectF textRect = brf(text(), _font, _maxWidth);
|
||||
QRectF textRect = brf(text(), font(), _maxWidth);
|
||||
|
||||
switch (_anchor) {
|
||||
case Text::Center:
|
||||
@ -101,9 +101,10 @@ QRectF TextPointItem::computeTextRect(BoundingRectFunction brf) const
|
||||
|
||||
TextPointItem::TextPointItem(const QString &text, const QPointF &pos,
|
||||
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)
|
||||
{
|
||||
setFont(font);
|
||||
_boundingRect = computeTextRect(fuzzyBoundingRect);
|
||||
|
||||
if (!_icon.isNull()) {
|
||||
@ -129,7 +130,7 @@ void TextPointItem::paint(QPainter *painter) const
|
||||
} else
|
||||
textRect = computeTextRect(fuzzyBoundingRect);
|
||||
|
||||
painter->setFont(_font);
|
||||
painter->setPen(_pen);
|
||||
painter->setFont(font());
|
||||
painter->setPen(pen());
|
||||
painter->drawText(textRect, FLAGS, text());
|
||||
}
|
||||
|
@ -17,8 +17,6 @@ public:
|
||||
QPainterPath shape() const {return _shape;}
|
||||
void paint(QPainter *painter) const;
|
||||
|
||||
void setPen(const QPen &pen) {_pen = pen;}
|
||||
|
||||
private:
|
||||
typedef QRectF (*BoundingRectFunction)(const QString &, const QFont &, int);
|
||||
|
||||
@ -32,8 +30,6 @@ private:
|
||||
QPointF _pos;
|
||||
QPainterPath _shape;
|
||||
QRectF _boundingRect;
|
||||
QFont _font;
|
||||
QPen _pen;
|
||||
QImage _icon;
|
||||
int _maxWidth;
|
||||
Text::Anchor _anchor;
|
||||
|
Loading…
Reference in New Issue
Block a user