1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Precompute all compute-intensive stuff

This commit is contained in:
Martin Tůma 2018-05-18 20:08:52 +02:00
parent 650eb1c302
commit 0156d2fbc0
4 changed files with 126 additions and 126 deletions

View File

@ -11,23 +11,28 @@
#define XTICKS 15 #define XTICKS 15
#define YTICKS 10 #define YTICKS 10
struct Label { class Ticks
double min; {
double max; public:
double d; Ticks(double min, double max, int count);
int count() const {return ((int)((_max - _min) / _d)) + 1;}
double val(int i) const {return _min + i * _d;}
double min() const {return _min;}
double max() const {return _max;}
private:
double _min;
double _max;
double _d;
}; };
static struct Label label(double min, double max, int ticks) Ticks::Ticks(double min, double max, int count)
{ {
double range; double range = niceNum(max - min, 0);
struct Label l; _d = niceNum(range / count, 1);
_min = ceil(min / _d) * _d;
range = niceNum(max - min, 0); _max = floor(max / _d) * _d;
l.d = niceNum(range / ticks, 1);
l.min = ceil(min / l.d) * l.d;
l.max = floor(max / l.d) * l.d;
return l;
} }
@ -48,6 +53,16 @@ void AxisItem::setRange(const RangeF &range)
{ {
prepareGeometryChange(); prepareGeometryChange();
_range = range; _range = range;
QFontMetrics fm(_font);
Ticks ticks(_range.min(), _range.max(), (_type == X) ? XTICKS : YTICKS);
_ticks = QVector<Tick>(ticks.count());
for (int i = 0; i < ticks.count(); i++) {
Tick &t = _ticks[i];
t.value = ticks.val(i);
t.boundingBox = fm.tightBoundingRect(QString::number(t.value));
}
updateBoundingRect(); updateBoundingRect();
update(); update();
} }
@ -63,7 +78,9 @@ void AxisItem::setSize(qreal size)
void AxisItem::setLabel(const QString& label) void AxisItem::setLabel(const QString& label)
{ {
prepareGeometryChange(); prepareGeometryChange();
QFontMetrics fm(_font);
_label = label; _label = label;
_labelBB = fm.tightBoundingRect(label);
updateBoundingRect(); updateBoundingRect();
update(); update();
} }
@ -71,31 +88,18 @@ void AxisItem::setLabel(const QString& label)
void AxisItem::updateBoundingRect() void AxisItem::updateBoundingRect()
{ {
QFontMetrics fm(_font); QFontMetrics fm(_font);
QRect ss, es, ls; QRect es = _ticks.isEmpty() ? QRect() : _ticks.last().boundingBox;
struct Label l; QRect ss = _ticks.isEmpty() ? QRect() : _ticks.first().boundingBox;
QRect ls(_labelBB);
l = label(_range.min(), _range.max(), (_type == X) ? XTICKS : YTICKS);
es = fm.tightBoundingRect(QString::number(l.max));
ss = fm.tightBoundingRect(QString::number(l.min));
ls = fm.tightBoundingRect(_label);
if (_type == X) { if (_type == X) {
_boundingRect = QRectF(-ss.width()/2, -TICK/2, _boundingRect = QRectF(-ss.width()/2, -TICK/2, _size + es.width()/2
_size + es.width()/2 + ss.width()/2, + ss.width()/2, ls.height() + es.height() - fm.descent() + TICK
ls.height() + es.height() - fm.descent() + TICK + 2*PADDING + 1); + 2*PADDING + 1);
} else { } else {
int mtw = 0; int mtw = 0;
QRect ts; for (int i = 0; i < _ticks.count(); i++)
qreal val; mtw = qMax(_ticks.at(i).boundingBox.width(), mtw);
for (int i = 0; i < ((l.max - l.min) / l.d) + 1; i++) {
val = l.min + i * l.d;
QString str = QString::number(val);
ts = fm.tightBoundingRect(str);
mtw = qMax(ts.width(), mtw);
}
_boundingRect = QRectF(-(ls.height() + mtw + 2*PADDING + TICK/2), _boundingRect = QRectF(-(ls.height() + mtw + 2*PADDING + TICK/2),
-(_size + es.height()/2 + fm.descent()), ls.height() + mtw + 2*PADDING -(_size + es.height()/2 + fm.descent()), ls.height() + mtw + 2*PADDING
+ TICK, _size + es.height()/2 + fm.descent() + ss.height()/2); + TICK, _size + es.height()/2 + fm.descent() + ss.height()/2);
@ -108,8 +112,6 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
Q_UNUSED(option); Q_UNUSED(option);
Q_UNUSED(widget); Q_UNUSED(widget);
QFontMetrics fm(_font); QFontMetrics fm(_font);
QRect ls(fm.tightBoundingRect(_label));
qreal range = _range.size();
QRect ts; QRect ts;
@ -120,40 +122,39 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
if (_type == X) { if (_type == X) {
painter->drawLine(0, 0, _size, 0); painter->drawLine(0, 0, _size, 0);
Label l = label(_range.min(), _range.max(), XTICKS); for (int i = 0; i < _ticks.count(); i++) {
for (int i = 0; i < ((l.max - l.min) / l.d) + 1; i++) { qreal val = _ticks.at(i).value;
qreal val = l.min + i * l.d; ts = _ticks.at(i).boundingBox;
QString str = QString::number(val);
painter->drawLine((_size/range) * (val - _range.min()), TICK/2, painter->drawLine((_size/_range.size()) * (val - _range.min()),
(_size/range) * (val - _range.min()), -TICK/2); TICK/2, (_size/_range.size()) * (val - _range.min()), -TICK/2);
ts = fm.tightBoundingRect(str); painter->drawText(((_size/_range.size()) * (val - _range.min()))
painter->drawText(((_size/range) * (val - _range.min())) - (ts.width()/2), ts.height() + TICK/2 + PADDING,
- (ts.width()/2), ts.height() + TICK/2 + PADDING, str); QString::number(val));
} }
painter->drawText(_size/2 - ls.width()/2, ls.height() + ts.height() painter->drawText(_size/2 - _labelBB.width()/2, _labelBB.height()
- 2*fm.descent() + TICK/2 + 2*PADDING, _label); + ts.height() - 2*fm.descent() + TICK/2 + 2*PADDING, _label);
} else { } else {
painter->drawLine(0, 0, 0, -_size); painter->drawLine(0, 0, 0, -_size);
Label l = label(_range.min(), _range.max(), YTICKS);
int mtw = 0; int mtw = 0;
for (int i = 0; i < ((l.max - l.min) / l.d) + 1; i++) { for (int i = 0; i < _ticks.count(); i++) {
qreal val = l.min + i * l.d; qreal val = _ticks.at(i).value;
QString str = QString::number(val); ts = _ticks.at(i).boundingBox;
painter->drawLine(TICK/2, -((_size/range) * (val - _range.min())),
-TICK/2, -((_size/range) * (val - _range.min())));
ts = fm.tightBoundingRect(str);
mtw = qMax(ts.width(), mtw); mtw = qMax(ts.width(), mtw);
painter->drawText(-(ts.width() + PADDING + TICK/2), -((_size/range)
* (val - _range.min())) + (ts.height()/2), str); painter->drawLine(TICK/2, -((_size/_range.size())
* (val - _range.min())), -TICK/2, -((_size/_range.size())
* (val - _range.min())));
painter->drawText(-(ts.width() + PADDING + TICK/2),
-((_size/_range.size()) * (val - _range.min())) + (ts.height()/2),
QString::number(val));
} }
painter->rotate(-90); painter->rotate(-90);
painter->drawText(_size/2 - ls.width()/2, -(mtw + 2*PADDING + TICK/2), painter->drawText(_size/2 - _labelBB.width()/2, -(mtw + 2*PADDING
_label); + TICK/2), _label);
painter->rotate(90); painter->rotate(90);
} }
@ -165,46 +166,28 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QSizeF AxisItem::margin() const QSizeF AxisItem::margin() const
{ {
QFont font; QFontMetrics fm(_font);
font.setPixelSize(FONT_SIZE); QRect es = _ticks.isEmpty() ? QRect() : _ticks.last().boundingBox;
QFontMetrics fm(font);
QRect ss, es, ls;
struct Label l;
l = label(_range.min(), _range.max(), (_type == X) ? XTICKS : YTICKS);
es = fm.tightBoundingRect(QString::number(l.max));
ss = fm.tightBoundingRect(QString::number(l.min));
ls = fm.tightBoundingRect(_label);
if (_type == X) { if (_type == X) {
return QSizeF(es.width()/2, return QSizeF(es.width()/2, _labelBB.height() + es.height()
ls.height() + es.height() - fm.descent() + TICK/2 + 2*PADDING); - fm.descent() + TICK/2 + 2*PADDING);
} else { } else {
int mtw = 0; int mtw = 0;
QRect ts; for (int i = 0; i < _ticks.count(); i++)
qreal val; mtw = qMax(_ticks.at(i).boundingBox.width(), mtw);
for (int i = 0; i < ((l.max - l.min) / l.d) + 1; i++) { return QSizeF(_labelBB.height() -fm.descent() + mtw + 2*PADDING
val = l.min + i * l.d;
QString str = QString::number(val);
ts = fm.tightBoundingRect(str);
mtw = qMax(ts.width(), mtw);
}
return QSizeF(ls.height() -fm.descent() + mtw + 2*PADDING
+ TICK/2, es.height()/2 + fm.descent()); + TICK/2, es.height()/2 + fm.descent());
} }
} }
QList<qreal> AxisItem::ticks() const QList<qreal> AxisItem::ticks() const
{ {
struct Label l;
QList<qreal> list; QList<qreal> list;
l = label(_range.min(), _range.max(), (_type == X) ? XTICKS : YTICKS); for (int i = 0; i < _ticks.count(); i++)
for (int i = 0; i < ((l.max - l.min) / l.d) + 1; i++) list.append(((_size/_range.size()) * (_ticks.at(i).value
list.append(((_size/_range.size()) * ((l.min + i * l.d)
- _range.min()))); - _range.min())));
return list; return list;

View File

@ -2,6 +2,7 @@
#define AXISITEM_H #define AXISITEM_H
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QVector>
#include "common/range.h" #include "common/range.h"
class AxisItem : public QGraphicsItem class AxisItem : public QGraphicsItem
@ -23,12 +24,19 @@ public:
QList<qreal> ticks() const; QList<qreal> ticks() const;
private: private:
struct Tick {
double value;
QRect boundingBox;
};
void updateBoundingRect(); void updateBoundingRect();
Type _type; Type _type;
RangeF _range; RangeF _range;
qreal _size; qreal _size;
QString _label; QString _label;
QRect _labelBB;
QVector<Tick> _ticks;
QRectF _boundingRect; QRectF _boundingRect;
QFont _font; QFont _font;
}; };

View File

@ -26,20 +26,6 @@ ScaleItem::ScaleItem(QGraphicsItem *parent) : QGraphicsItem(parent)
#endif // Q_OS_MAC #endif // Q_OS_MAC
} }
void ScaleItem::updateBoundingRect()
{
QFontMetrics fm(_font);
QRect ss, es, us;
ss = fm.tightBoundingRect(QString::number(0));
es = fm.tightBoundingRect(QString::number(_length * SEGMENTS));
us = fm.tightBoundingRect(units());
_boundingRect = QRectF(-ss.width()/2, 0, _width * SEGMENTS + ss.width()/2
+ qMax(us.width() + PADDING, es.width()/2) + 1, SCALE_HEIGHT + PADDING
+ ss.height() + 2*fm.descent());
}
void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget) QWidget *widget)
{ {
@ -53,13 +39,13 @@ void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->setFont(_font); painter->setFont(_font);
painter->setPen(QPen(Qt::black, BORDER_WIDTH)); painter->setPen(QPen(Qt::black, BORDER_WIDTH));
for (int i = 0; i <= SEGMENTS; i++) { for (int i = 0; i < _ticks.size(); i++) {
QString label = QString::number(_length * i); br = _ticks.at(i).boundingBox;
br = fm.tightBoundingRect(label); painter->drawText(_width * i - br.width()/2, br.height() + 1,
painter->drawText(_width * i - br.width()/2, br.height() + 1, label); QString::number(_ticks.at(i).value));
} }
painter->drawText(_width * SEGMENTS + PADDING, SCALE_HEIGHT + PADDING painter->drawText(_width * SEGMENTS + PADDING, SCALE_HEIGHT + PADDING
+ br.height() + fm.descent(), units()); + br.height() + fm.descent(), _unitsStr);
painter->drawRect(QRectF(0, br.height() + PADDING, SEGMENTS * _width, painter->drawRect(QRectF(0, br.height() + PADDING, SEGMENTS * _width,
SCALE_HEIGHT)); SCALE_HEIGHT));
@ -73,19 +59,6 @@ void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
*/ */
} }
QString ScaleItem::units() const
{
if (_units == Imperial)
return _scale ? qApp->translate("ScaleItem", "mi")
: qApp->translate("ScaleItem", "ft");
else if (_units == Nautical)
return _scale ? qApp->translate("ScaleItem", "nmi")
: qApp->translate("ScaleItem", "ft");
else
return _scale ? qApp->translate("ScaleItem", "km")
: qApp->translate("ScaleItem", "m");
}
void ScaleItem::computeScale() void ScaleItem::computeScale()
{ {
qreal res = _res * pow(2, -_digitalZoom); qreal res = _res * pow(2, -_digitalZoom);
@ -123,21 +96,50 @@ void ScaleItem::computeScale()
} }
} }
void ScaleItem::updateCache()
{
QFontMetrics fm(_font);
_ticks = QVector<Tick>(SEGMENTS + 1);
for (int i = 0; i < _ticks.size(); i++) {
Tick &t = _ticks[i];
t.value = _length * i;
t.boundingBox = fm.tightBoundingRect(QString::number(t.value));
}
if (_units == Imperial)
_unitsStr = _scale ? qApp->translate("ScaleItem", "mi")
: qApp->translate("ScaleItem", "ft");
else if (_units == Nautical)
_unitsStr = _scale ? qApp->translate("ScaleItem", "nmi")
: qApp->translate("ScaleItem", "ft");
else
_unitsStr = _scale ? qApp->translate("ScaleItem", "km")
: qApp->translate("ScaleItem", "m");
_unitsBB = fm.tightBoundingRect(_unitsStr);
QRect ss = _ticks.isEmpty() ? QRect() : _ticks.first().boundingBox;
QRect es = _ticks.isEmpty() ? QRect() : _ticks.last().boundingBox;
_boundingRect = QRectF(-ss.width()/2, 0, _width * SEGMENTS + ss.width()/2
+ qMax(_unitsBB.width() + PADDING, es.width()/2) + 1, SCALE_HEIGHT
+ PADDING + ss.height() + 2*fm.descent());
}
void ScaleItem::setResolution(qreal res) void ScaleItem::setResolution(qreal res)
{ {
prepareGeometryChange(); prepareGeometryChange();
_res = res; _res = res;
computeScale(); computeScale();
updateBoundingRect(); updateCache();
update(); update();
} }
void ScaleItem::setUnits(enum Units units) void ScaleItem::setUnits(Units units)
{ {
prepareGeometryChange(); prepareGeometryChange();
_units = units; _units = units;
computeScale(); computeScale();
updateBoundingRect(); updateCache();
update(); update();
} }
@ -146,7 +148,7 @@ void ScaleItem::setDigitalZoom(qreal zoom)
prepareGeometryChange(); prepareGeometryChange();
_digitalZoom = zoom; _digitalZoom = zoom;
computeScale(); computeScale();
updateBoundingRect(); updateCache();
update(); update();
setScale(pow(2, -_digitalZoom)); setScale(pow(2, -_digitalZoom));

View File

@ -14,13 +14,17 @@ public:
QWidget *widget); QWidget *widget);
void setResolution(qreal res); void setResolution(qreal res);
void setUnits(enum Units units); void setUnits(Units units);
void setDigitalZoom(qreal zoom); void setDigitalZoom(qreal zoom);
private: private:
void updateBoundingRect(); struct Tick {
double value;
QRect boundingBox;
};
void computeScale(); void computeScale();
QString units() const; void updateCache();
qreal _res; qreal _res;
qreal _width; qreal _width;
@ -30,6 +34,9 @@ private:
qreal _digitalZoom; qreal _digitalZoom;
QRectF _boundingRect; QRectF _boundingRect;
QFont _font; QFont _font;
QVector<Tick> _ticks;
QRect _unitsBB;
QString _unitsStr;
}; };
#endif // SCALEITEM_H #endif // SCALEITEM_H