mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Fixed graph line distortion in PDF output
This commit is contained in:
parent
cb52ad8bc5
commit
be3c101c07
@ -15,6 +15,7 @@ public:
|
|||||||
qreal s() const {return _s;}
|
qreal s() const {return _s;}
|
||||||
qreal t() const {return _t;}
|
qreal t() const {return _t;}
|
||||||
qreal y() const {return _y;}
|
qreal y() const {return _y;}
|
||||||
|
qreal x(GraphType type) const {return (type == Distance) ? _s : _t;}
|
||||||
|
|
||||||
void setS(qreal s) {_s = s;}
|
void setS(qreal s) {_s = s;}
|
||||||
void setT(qreal t) {_t = t;}
|
void setT(qreal t) {_t = t;}
|
||||||
|
@ -5,37 +5,6 @@
|
|||||||
#define GRAPH_WIDTH 1
|
#define GRAPH_WIDTH 1
|
||||||
#define HOVER_WIDTH 2
|
#define HOVER_WIDTH 2
|
||||||
|
|
||||||
static qreal yAtX(const QPainterPath &path, qreal x)
|
|
||||||
{
|
|
||||||
int low = 0;
|
|
||||||
int high = path.elementCount() - 1;
|
|
||||||
int mid = 0;
|
|
||||||
|
|
||||||
Q_ASSERT(high > low);
|
|
||||||
Q_ASSERT(x >= path.elementAt(low).x && x <= path.elementAt(high).x);
|
|
||||||
|
|
||||||
while (low <= high) {
|
|
||||||
mid = low + ((high - low) / 2);
|
|
||||||
const QPainterPath::Element &e = path.elementAt(mid);
|
|
||||||
if (e.x > x)
|
|
||||||
high = mid - 1;
|
|
||||||
else if (e.x < x)
|
|
||||||
low = mid + 1;
|
|
||||||
else
|
|
||||||
return e.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
QLineF l;
|
|
||||||
if (path.elementAt(mid).x < x)
|
|
||||||
l = QLineF(path.elementAt(mid).x, path.elementAt(mid).y,
|
|
||||||
path.elementAt(mid+1).x, path.elementAt(mid+1).y);
|
|
||||||
else
|
|
||||||
l = QLineF(path.elementAt(mid-1).x, path.elementAt(mid-1).y,
|
|
||||||
path.elementAt(mid).x, path.elementAt(mid).y);
|
|
||||||
|
|
||||||
return l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasTime(const Graph &graph)
|
static bool hasTime(const Graph &graph)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < graph.count(); i++)
|
for (int i = 0; i < graph.count(); i++)
|
||||||
@ -49,20 +18,16 @@ GraphItem::GraphItem(const Graph &graph, QGraphicsItem *parent)
|
|||||||
: QGraphicsObject(parent)
|
: QGraphicsObject(parent)
|
||||||
{
|
{
|
||||||
_id = 0;
|
_id = 0;
|
||||||
_type = Distance;
|
|
||||||
|
|
||||||
_pen = QPen(Qt::black, GRAPH_WIDTH);
|
_pen = QPen(Qt::black, GRAPH_WIDTH);
|
||||||
_pen.setCosmetic(true);
|
|
||||||
|
|
||||||
_distancePath.moveTo(graph.first().s(), -graph.first().y());
|
_type = Distance;
|
||||||
for (int i = 1; i < graph.size(); i++)
|
_graph = graph;
|
||||||
_distancePath.lineTo(graph.at(i).s(), -graph.at(i).y());
|
_sx = 1.0; _sy = 1.0;
|
||||||
|
_time = hasTime(_graph);
|
||||||
|
|
||||||
if (hasTime(graph)) {
|
updatePath();
|
||||||
_timePath.moveTo(graph.first().t(), -graph.first().y());
|
updateBounds();
|
||||||
for (int i = 1; i < graph.size(); i++)
|
|
||||||
_timePath.lineTo(graph.at(i).t(), -graph.at(i).y());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||||
@ -72,7 +37,7 @@ void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||||||
Q_UNUSED(widget);
|
Q_UNUSED(widget);
|
||||||
|
|
||||||
painter->setPen(_pen);
|
painter->setPen(_pen);
|
||||||
painter->drawPath((_type == Distance) ? _distancePath : _timePath);
|
painter->drawPath(_path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
QPen p = QPen(QBrush(Qt::red), 0);
|
QPen p = QPen(QBrush(Qt::red), 0);
|
||||||
@ -84,7 +49,10 @@ void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||||||
void GraphItem::setGraphType(GraphType type)
|
void GraphItem::setGraphType(GraphType type)
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
||||||
_type = type;
|
_type = type;
|
||||||
|
updatePath();
|
||||||
|
updateBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphItem::setColor(const QColor &color)
|
void GraphItem::setColor(const QColor &color)
|
||||||
@ -95,37 +63,62 @@ void GraphItem::setColor(const QColor &color)
|
|||||||
|
|
||||||
qreal GraphItem::yAtX(qreal x)
|
qreal GraphItem::yAtX(qreal x)
|
||||||
{
|
{
|
||||||
return ::yAtX((_type == Distance) ? _distancePath : _timePath, x);
|
int low = 0;
|
||||||
|
int high = _graph.count() - 1;
|
||||||
|
int mid = 0;
|
||||||
|
|
||||||
|
Q_ASSERT(high > low);
|
||||||
|
Q_ASSERT(x >= _graph.at(low).x(_type) && x <= _graph.at(high).x(_type));
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
mid = low + ((high - low) / 2);
|
||||||
|
const GraphPoint &p = _graph.at(mid);
|
||||||
|
if (p.x(_type) > x)
|
||||||
|
high = mid - 1;
|
||||||
|
else if (p.x(_type) < x)
|
||||||
|
low = mid + 1;
|
||||||
|
else
|
||||||
|
return -p.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
QLineF l;
|
||||||
|
if (_graph.at(mid).x(_type) < x)
|
||||||
|
l = QLineF(_graph.at(mid).x(_type), _graph.at(mid).y(),
|
||||||
|
_graph.at(mid+1).x(_type), _graph.at(mid+1).y());
|
||||||
|
else
|
||||||
|
l = QLineF(_graph.at(mid-1).x(_type), _graph.at(mid-1).y(),
|
||||||
|
_graph.at(mid).x(_type), _graph.at(mid).y());
|
||||||
|
|
||||||
|
return -l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal GraphItem::distanceAtTime(qreal time)
|
qreal GraphItem::distanceAtTime(qreal time)
|
||||||
{
|
{
|
||||||
int low = 0;
|
int low = 0;
|
||||||
int high = _timePath.elementCount() - 1;
|
int high = _graph.count() - 1;
|
||||||
int mid = 0;
|
int mid = 0;
|
||||||
|
|
||||||
Q_ASSERT(high > low);
|
Q_ASSERT(high > low);
|
||||||
Q_ASSERT(time >= _timePath.elementAt(low).x
|
Q_ASSERT(time >= _graph.at(low).t() && time <= _graph.at(high).t());
|
||||||
&& time <= _timePath.elementAt(high).x);
|
|
||||||
|
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
mid = low + ((high - low) / 2);
|
mid = low + ((high - low) / 2);
|
||||||
const QPainterPath::Element &e = _timePath.elementAt(mid);
|
const GraphPoint &p = _graph.at(mid);
|
||||||
if (e.x > time)
|
if (p.t() > time)
|
||||||
high = mid - 1;
|
high = mid - 1;
|
||||||
else if (e.x < time)
|
else if (p.t() < time)
|
||||||
low = mid + 1;
|
low = mid + 1;
|
||||||
else
|
else
|
||||||
return _distancePath.elementAt(mid).x;
|
return _graph.at(mid).s();
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineF l;
|
QLineF l;
|
||||||
if (_timePath.elementAt(mid).x < time)
|
if (_graph.at(mid).t() < time)
|
||||||
l = QLineF(_timePath.elementAt(mid).x, _distancePath.elementAt(mid).x,
|
l = QLineF(_graph.at(mid).t(), _graph.at(mid).s(), _graph.at(mid+1).t(),
|
||||||
_timePath.elementAt(mid+1).x, _distancePath.elementAt(mid+1).x);
|
_graph.at(mid+1).s());
|
||||||
else
|
else
|
||||||
l = QLineF(_timePath.elementAt(mid-1).x, _distancePath.elementAt(mid-1).x,
|
l = QLineF(_graph.at(mid-1).t(), _graph.at(mid-1).s(),
|
||||||
_timePath.elementAt(mid).x, _distancePath.elementAt(mid).x);
|
_graph.at(mid).t(), _graph.at(mid).s());
|
||||||
|
|
||||||
return l.pointAt((time - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
|
return l.pointAt((time - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
|
||||||
}
|
}
|
||||||
@ -133,15 +126,13 @@ qreal GraphItem::distanceAtTime(qreal time)
|
|||||||
void GraphItem::emitSliderPositionChanged(qreal pos)
|
void GraphItem::emitSliderPositionChanged(qreal pos)
|
||||||
{
|
{
|
||||||
if (_type == Time) {
|
if (_type == Time) {
|
||||||
if (!_timePath.isEmpty()) {
|
if (_time) {
|
||||||
if (pos <= _timePath.elementAt(_timePath.elementCount() - 1).x)
|
if (pos <= _graph.last().t())
|
||||||
emit sliderPositionChanged(distanceAtTime(pos));
|
emit sliderPositionChanged(distanceAtTime(pos));
|
||||||
else
|
else
|
||||||
emit sliderPositionChanged(_distancePath.elementAt(
|
emit sliderPositionChanged(_graph.last().s() + 1);
|
||||||
_distancePath.elementCount() - 1).x + 1);
|
|
||||||
} else
|
} else
|
||||||
emit sliderPositionChanged(_distancePath.elementAt(
|
emit sliderPositionChanged(_graph.last().s() + 1);
|
||||||
_distancePath.elementCount() - 1).x + 1);
|
|
||||||
} else
|
} else
|
||||||
emit sliderPositionChanged(pos);
|
emit sliderPositionChanged(pos);
|
||||||
}
|
}
|
||||||
@ -158,3 +149,47 @@ void GraphItem::selected(bool selected)
|
|||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphItem::setScale(qreal sx, qreal sy)
|
||||||
|
{
|
||||||
|
if (_sx == sx && _sy == sy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
prepareGeometryChange();
|
||||||
|
|
||||||
|
_sx = sx; _sy = sy;
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphItem::updatePath()
|
||||||
|
{
|
||||||
|
_path = QPainterPath();
|
||||||
|
|
||||||
|
if (_type == Time && !_time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_path.moveTo(_graph.first().x(_type) * _sx, -_graph.first().y() * _sy);
|
||||||
|
for (int i = 1; i < _graph.size(); i++)
|
||||||
|
_path.lineTo(_graph.at(i).x(_type) * _sx, -_graph.at(i).y() * _sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphItem::updateBounds()
|
||||||
|
{
|
||||||
|
if (_type == Time && !_time) {
|
||||||
|
_bounds = QRectF();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal bottom, top, left, right;
|
||||||
|
|
||||||
|
QPointF p = QPointF(_graph.first().x(_type), -_graph.first().y());
|
||||||
|
bottom = p.y(); top = p.y(); left = p.x(); right = p.x();
|
||||||
|
|
||||||
|
for (int i = 1; i < _graph.size(); i++) {
|
||||||
|
p = QPointF(_graph.at(i).x(_type), -_graph.at(i).y());
|
||||||
|
bottom = qMax(bottom, p.y()); top = qMin(top, p.y());
|
||||||
|
right = qMax(right, p.x()); left = qMin(left, p.x());
|
||||||
|
}
|
||||||
|
|
||||||
|
_bounds = QRectF(QPointF(left, top), QPointF(right, bottom));
|
||||||
|
}
|
||||||
|
@ -13,11 +13,13 @@ public:
|
|||||||
GraphItem(const Graph &graph, QGraphicsItem *parent = 0);
|
GraphItem(const Graph &graph, QGraphicsItem *parent = 0);
|
||||||
|
|
||||||
QRectF boundingRect() const
|
QRectF boundingRect() const
|
||||||
{return (_type == Distance) ? _distancePath.boundingRect()
|
{return _path.boundingRect();}
|
||||||
: _timePath.boundingRect();}
|
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||||
QWidget *widget);
|
QWidget *widget);
|
||||||
|
|
||||||
|
const QRectF &bounds() const {return _bounds;}
|
||||||
|
void setScale(qreal sx, qreal sy);
|
||||||
|
|
||||||
void setGraphType(GraphType type);
|
void setGraphType(GraphType type);
|
||||||
int id() const {return _id;}
|
int id() const {return _id;}
|
||||||
void setId(int id) {_id = id;}
|
void setId(int id) {_id = id;}
|
||||||
@ -34,10 +36,19 @@ public slots:
|
|||||||
void selected(bool selected);
|
void selected(bool selected);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updatePath();
|
||||||
|
void updateBounds();
|
||||||
|
|
||||||
int _id;
|
int _id;
|
||||||
QPen _pen;
|
QPen _pen;
|
||||||
QPainterPath _distancePath, _timePath;
|
|
||||||
|
Graph _graph;
|
||||||
GraphType _type;
|
GraphType _type;
|
||||||
|
bool _time;
|
||||||
|
|
||||||
|
QPainterPath _path;
|
||||||
|
QRectF _bounds;
|
||||||
|
qreal _sx, _sy;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GRAPHITEM_H
|
#endif // GRAPHITEM_H
|
||||||
|
@ -153,7 +153,7 @@ void GraphView::setGraphType(GraphType type)
|
|||||||
for (int i = 0; i < _graphs.count(); i++) {
|
for (int i = 0; i < _graphs.count(); i++) {
|
||||||
_graphs.at(i)->setGraphType(type);
|
_graphs.at(i)->setGraphType(type);
|
||||||
if (_graphs.at(i)->scene() == _scene)
|
if (_graphs.at(i)->scene() == _scene)
|
||||||
_bounds |= _graphs.at(i)->boundingRect();
|
_bounds |= _graphs.at(i)->bounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Distance)
|
if (type == Distance)
|
||||||
@ -186,7 +186,7 @@ void GraphView::loadGraph(const Graph &graph, PathItem *path, int id)
|
|||||||
if (!_hide.contains(id)) {
|
if (!_hide.contains(id)) {
|
||||||
_visible.append(gi);
|
_visible.append(gi);
|
||||||
_scene->addItem(gi);
|
_scene->addItem(gi);
|
||||||
_bounds |= gi->boundingRect();
|
_bounds |= gi->bounds();
|
||||||
setXUnits();
|
setXUnits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ void GraphView::showGraph(bool show, int id)
|
|||||||
else {
|
else {
|
||||||
addItem(gi);
|
addItem(gi);
|
||||||
_visible.append(gi);
|
_visible.append(gi);
|
||||||
_bounds |= gi->boundingRect();
|
_bounds |= gi->bounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,8 +241,7 @@ void GraphView::redraw(const QSizeF &size)
|
|||||||
QRectF r;
|
QRectF r;
|
||||||
QSizeF mx, my;
|
QSizeF mx, my;
|
||||||
RangeF rx, ry;
|
RangeF rx, ry;
|
||||||
QTransform transform;
|
qreal sx, sy;
|
||||||
qreal xs, ys;
|
|
||||||
|
|
||||||
|
|
||||||
if (_visible.isEmpty() || _bounds.isNull()) {
|
if (_visible.isEmpty() || _bounds.isNull()) {
|
||||||
@ -275,20 +274,19 @@ void GraphView::redraw(const QSizeF &size)
|
|||||||
r.adjust(0, -(_minYRange/2 - r.height()/2), 0,
|
r.adjust(0, -(_minYRange/2 - r.height()/2), 0,
|
||||||
_minYRange/2 - r.height()/2);
|
_minYRange/2 - r.height()/2);
|
||||||
|
|
||||||
xs = (size.width() - (my.width() + mx.width())) / r.width();
|
sx = (size.width() - (my.width() + mx.width())) / r.width();
|
||||||
ys = (size.height() - (mx.height() + my.height())
|
sy = (size.height() - (mx.height() + my.height())
|
||||||
- _info->boundingRect().height()) / r.height();
|
- _info->boundingRect().height()) / r.height();
|
||||||
transform.scale(xs, ys);
|
|
||||||
|
|
||||||
for (int i = 0; i < _visible.size(); i++)
|
for (int i = 0; i < _visible.size(); i++)
|
||||||
_visible.at(i)->setTransform(transform);
|
_visible.at(i)->setScale(sx, sy);
|
||||||
|
|
||||||
QPointF p(r.left() * xs, r.top() * ys);
|
QPointF p(r.left() * sx, r.top() * sy);
|
||||||
QSizeF s(r.width() * xs, r.height() * ys);
|
QSizeF s(r.width() * sx, r.height() * sy);
|
||||||
r = QRectF(p, s);
|
r = QRectF(p, s);
|
||||||
if (r.height() < _minYRange * ys)
|
if (r.height() < _minYRange * sy)
|
||||||
r.adjust(0, -(_minYRange/2 * ys - r.height()/2), 0,
|
r.adjust(0, -(_minYRange/2 * sy - r.height()/2), 0,
|
||||||
(_minYRange/2) * ys - r.height()/2);
|
(_minYRange/2) * sy - r.height()/2);
|
||||||
|
|
||||||
_xAxis->setSize(r.width());
|
_xAxis->setSize(r.width());
|
||||||
_yAxis->setSize(r.height());
|
_yAxis->setSize(r.height());
|
||||||
@ -368,7 +366,7 @@ void GraphView::updateSliderInfo()
|
|||||||
if (!_sliderInfo->isVisible())
|
if (!_sliderInfo->isVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QRectF br(_visible.first()->boundingRect());
|
QRectF br(_visible.first()->bounds());
|
||||||
if (br.height() < _minYRange)
|
if (br.height() < _minYRange)
|
||||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||||
_minYRange/2 - br.height()/2);
|
_minYRange/2 - br.height()/2);
|
||||||
|
Loading…
Reference in New Issue
Block a user