openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

84 lines
2.6 KiB

#include "tools/cabana/chart/sparkline.h"
#include <limits>
#include <QPainter>
#include "tools/cabana/streams/abstractstream.h"
void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size) {
const auto &msgs = can->events(msg_id);
uint64_t ts = (last_msg_ts + can->routeStartTime()) * 1e9;
uint64_t first_ts = (ts > range * 1e9) ? ts - range * 1e9 : 0;
auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), first_ts, [](auto e, uint64_t ts) {
return e->mono_time < ts;
});
auto last = std::upper_bound(first, msgs.cend(), ts, [](uint64_t ts, auto e) {
return ts < e->mono_time;
});
bool update_values = last_ts != last_msg_ts || time_range != range;
last_ts = last_msg_ts;
time_range = range;
if (first != last) {
if (update_values) {
values.clear();
if (values.capacity() < std::distance(first, last)) {
values.reserve(std::distance(first, last) * 2);
}
min_val = std::numeric_limits<double>::max();
max_val = std::numeric_limits<double>::lowest();
for (auto it = first; it != last; ++it) {
const CanEvent *e = *it;
double value = 0;
if (sig->getValue(e->dat, e->size, &value)) {
values.emplace_back((e->mono_time - (*first)->mono_time) / 1e9, value);
if (min_val > value) min_val = value;
if (max_val < value) max_val = value;
}
}
if (min_val == max_val) {
min_val -= 1;
max_val += 1;
}
}
} else {
values.clear();
}
if (!values.empty()) {
render(sig->color, size);
} else {
pixmap = QPixmap();
min_val = -1;
max_val = 1;
}
}
void Sparkline::render(const QColor &color, QSize size) {
const double xscale = (size.width() - 1) / (double)time_range;
const double yscale = (size.height() - 3) / (max_val - min_val);
points.clear();
points.reserve(values.capacity());
for (auto &v : values) {
points.emplace_back(v.x() * xscale, 1 + std::abs(v.y() - max_val) * yscale);
}
qreal dpr = qApp->devicePixelRatio();
size *= dpr;
if (size != pixmap.size()) {
pixmap = QPixmap(size);
}
pixmap.setDevicePixelRatio(dpr);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing, points.size() < 500);
painter.setPen(color);
painter.drawPolyline(points.data(), points.size());
painter.setPen(QPen(color, 3));
if ((points.back().x() - points.front().x()) / points.size() > 8) {
painter.drawPoints(points.data(), points.size());
} else {
painter.drawPoint(points.back());
}
}