diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index bd4bf4aba..54966be57 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -562,6 +562,9 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even if (events->size()) { s.last_value_mono_time = events->back()->mono_time; } + if (!can->liveStreaming()) { + s.segment_tree.build(s.vals); + } s.series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); } } @@ -586,9 +589,15 @@ void ChartView::updateAxisY() { auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); - for (auto it = first; it != last; ++it) { - if (it->y() < min) min = it->y(); - if (it->y() > max) max = it->y(); + if (can->liveStreaming()) { + for (auto it = first; it != last; ++it) { + if (it->y() < min) min = it->y(); + if (it->y() > max) max = it->y(); + } + } else { + auto [min_y, max_y] = s.segment_tree.minmax(std::distance(s.vals.begin(), first), std::distance(s.vals.begin(), last)); + min = std::min(min, min_y); + max = std::max(max, max_y); } } if (min == std::numeric_limits::max()) min = 0; @@ -781,7 +790,7 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); qreal track_line_x = -1; for (auto &s : sigs) { - if (!s.track_pt.isNull() && s.series->isVisible()) { + if (!s.track_pt.isNull() && s.series->isVisible()) { painter->setBrush(s.series->color().darker(125)); painter->drawEllipse(s.track_pt, 5.5, 5.5); track_line_x = std::max(track_line_x, s.track_pt.x()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 76943c1fe..c86c19a04 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -46,6 +46,7 @@ public: QVector step_vals; uint64_t last_value_mono_time = 0; QPointF track_pt{}; + SegmentTree segment_tree; }; signals: diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 5e4f505d2..1a0b9d93e 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -67,6 +67,40 @@ void ChangeTracker::clear() { colors.clear(); } + +// SegmentTree + +void SegmentTree::build(const QVector &arr) { + size = arr.size(); + tree.resize(4 * size); // size of the tree is 4 times the size of the array + if (size > 0) { + build_tree(arr, 1, 0, size - 1); + } +} + +void SegmentTree::build_tree(const QVector &arr, int n, int left, int right) { + if (left == right) { + const double y = arr[left].y(); + tree[n] = {y, y}; + } else { + const int mid = (left + right) >> 1; + build_tree(arr, 2 * n, left, mid); + build_tree(arr, 2 * n + 1, mid + 1, right); + tree[n] = {std::min(tree[2 * n].first, tree[2 * n + 1].first), std::max(tree[2 * n].second, tree[2 * n + 1].second)}; + } +} + +std::pair SegmentTree::get_minmax(int n, int left, int right, int range_left, int range_right) const { + if (range_left > right || range_right < left) + return {std::numeric_limits::max(), std::numeric_limits::lowest()}; + if (range_left <= left && range_right >= right) + return tree[n]; + int mid = (left + right) >> 1; + auto l = get_minmax(2 * n, left, mid, range_left, range_right); + auto r = get_minmax(2 * n + 1, mid + 1, right, range_left, range_right); + return {std::min(l.first, r.first), std::max(l.second, r.second)}; +} + // MessageBytesDelegate MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 5eb5c3c5a..cf1b5d4b2 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -35,6 +35,19 @@ enum { BytesRole = Qt::UserRole + 2 }; +class SegmentTree { +public: + SegmentTree() = default; + void build(const QVector &arr); + inline std::pair minmax(int left, int right) const { return get_minmax(1, 0, size - 1, left, right); } + +private: + std::pair get_minmax(int n, int left, int right, int range_left, int range_right) const; + void build_tree(const QVector &arr, int n, int left, int right); + std::vector> tree; + int size = 0; +}; + class MessageBytesDelegate : public QStyledItemDelegate { Q_OBJECT public: