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

View File

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

View File

@ -26,20 +26,6 @@ ScaleItem::ScaleItem(QGraphicsItem *parent) : QGraphicsItem(parent)
#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,
QWidget *widget)
{
@ -53,13 +39,13 @@ void ScaleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->setFont(_font);
painter->setPen(QPen(Qt::black, BORDER_WIDTH));
for (int i = 0; i <= SEGMENTS; i++) {
QString label = QString::number(_length * i);
br = fm.tightBoundingRect(label);
painter->drawText(_width * i - br.width()/2, br.height() + 1, label);
for (int i = 0; i < _ticks.size(); i++) {
br = _ticks.at(i).boundingBox;
painter->drawText(_width * i - br.width()/2, br.height() + 1,
QString::number(_ticks.at(i).value));
}
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,
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()
{
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)
{
prepareGeometryChange();
_res = res;
computeScale();
updateBoundingRect();
updateCache();
update();
}
void ScaleItem::setUnits(enum Units units)
void ScaleItem::setUnits(Units units)
{
prepareGeometryChange();
_units = units;
computeScale();
updateBoundingRect();
updateCache();
update();
}
@ -146,7 +148,7 @@ void ScaleItem::setDigitalZoom(qreal zoom)
prepareGeometryChange();
_digitalZoom = zoom;
computeScale();
updateBoundingRect();
updateCache();
update();
setScale(pow(2, -_digitalZoom));

View File

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