2016-09-19 00:56:10 +02:00
|
|
|
#include <QPainter>
|
2016-08-19 19:48:44 +02:00
|
|
|
#include "graphitem.h"
|
|
|
|
|
2016-09-19 00:56:10 +02:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2016-09-19 23:35:04 +02:00
|
|
|
static bool hasTime(const Graph &graph)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < graph.count(); i++)
|
|
|
|
if (std::isnan(graph.at(i).t()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-19 00:56:10 +02:00
|
|
|
GraphItem::GraphItem(const Graph &graph, QGraphicsItem *parent)
|
|
|
|
: QGraphicsObject(parent)
|
|
|
|
{
|
|
|
|
_id = 0;
|
|
|
|
_pen = QPen(QBrush(Qt::SolidPattern), 0);
|
2016-09-19 23:35:04 +02:00
|
|
|
_type = Distance;
|
2016-09-19 00:56:10 +02:00
|
|
|
|
2016-09-19 23:35:04 +02:00
|
|
|
_distancePath.moveTo(graph.first().s(), -graph.first().y());
|
|
|
|
for (int i = 1; i < graph.size(); i++)
|
|
|
|
_distancePath.lineTo(graph.at(i).s(), -graph.at(i).y());
|
2016-09-19 00:56:10 +02:00
|
|
|
|
2016-09-19 23:35:04 +02:00
|
|
|
if (hasTime(graph)) {
|
|
|
|
_timePath.moveTo(graph.first().t(), -graph.first().y());
|
|
|
|
for (int i = 1; i < graph.size(); i++)
|
|
|
|
_timePath.lineTo(graph.at(i).t(), -graph.at(i).y());
|
2016-09-19 00:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|
|
|
QWidget *widget)
|
|
|
|
{
|
|
|
|
Q_UNUSED(option);
|
|
|
|
Q_UNUSED(widget);
|
|
|
|
|
|
|
|
painter->setPen(_pen);
|
2016-09-19 23:35:04 +02:00
|
|
|
painter->drawPath((_type == Distance) ? _distancePath : _timePath);
|
2016-09-19 00:56:10 +02:00
|
|
|
}
|
|
|
|
|
2016-08-19 19:48:44 +02:00
|
|
|
void GraphItem::setColor(const QColor &color)
|
|
|
|
{
|
|
|
|
QBrush brush(color, Qt::SolidPattern);
|
2016-09-19 00:56:10 +02:00
|
|
|
_pen.setBrush(brush);
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal GraphItem::yAtX(qreal x)
|
|
|
|
{
|
2016-09-19 23:35:04 +02:00
|
|
|
return ::yAtX((_type == Distance) ? _distancePath : _timePath, x);
|
2016-09-19 00:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qreal GraphItem::distanceAtTime(qreal time)
|
|
|
|
{
|
|
|
|
int low = 0;
|
|
|
|
int high = _timePath.elementCount() - 1;
|
|
|
|
int mid = 0;
|
|
|
|
|
|
|
|
Q_ASSERT(high > low);
|
|
|
|
Q_ASSERT(time >= _timePath.elementAt(low).x
|
|
|
|
&& time <= _timePath.elementAt(high).x);
|
|
|
|
|
|
|
|
while (low <= high) {
|
|
|
|
mid = low + ((high - low) / 2);
|
|
|
|
const QPainterPath::Element &e = _timePath.elementAt(mid);
|
|
|
|
if (e.x > time)
|
|
|
|
high = mid - 1;
|
|
|
|
else if (e.x < time)
|
|
|
|
low = mid + 1;
|
|
|
|
else
|
|
|
|
return _distancePath.elementAt(mid).x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_timePath.elementAt(mid).x < time)
|
|
|
|
return ((_distancePath.elementAt(mid+1).x
|
|
|
|
+ _distancePath.elementAt(mid).x) / 2.0);
|
|
|
|
else
|
|
|
|
return ((_distancePath.elementAt(mid).x
|
|
|
|
+ _distancePath.elementAt(mid-1).x) / 2.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphItem::emitSliderPositionChanged(qreal pos)
|
|
|
|
{
|
2016-09-19 23:35:04 +02:00
|
|
|
if (_type == Time) {
|
2016-09-19 00:56:10 +02:00
|
|
|
if (!_timePath.isEmpty()) {
|
|
|
|
if (pos <= _timePath.elementAt(_timePath.elementCount() - 1).x)
|
|
|
|
emit sliderPositionChanged(distanceAtTime(pos));
|
|
|
|
else
|
|
|
|
emit sliderPositionChanged(_distancePath.elementAt(
|
|
|
|
_distancePath.elementCount() - 1).x + 1);
|
|
|
|
} else
|
|
|
|
emit sliderPositionChanged(_distancePath.elementAt(
|
|
|
|
_distancePath.elementCount() - 1).x + 1);
|
|
|
|
} else
|
|
|
|
emit sliderPositionChanged(pos);
|
2016-08-19 19:48:44 +02:00
|
|
|
}
|