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 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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user