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:
parent
650eb1c302
commit
0156d2fbc0
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user