From: Jens Steinhauser Date: Sun, 30 Aug 2015 21:00:34 +0000 (+0200) Subject: Use a type with a greater resolution to represent time values X-Git-Tag: pulseview-0.3.0~126 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=60d9b99a32e551cffd2b537d3e157d578a761c9b;p=pulseview.git Use a type with a greater resolution to represent time values Fixes #627. --- diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp index ef497f72..0bb875da 100644 --- a/pv/data/decoderstack.cpp +++ b/pv/data/decoderstack.cpp @@ -119,7 +119,7 @@ double DecoderStack::samplerate() const return samplerate_; } -double DecoderStack::start_time() const +const pv::util::Timestamp& DecoderStack::start_time() const { return start_time_; } diff --git a/pv/data/decoderstack.hpp b/pv/data/decoderstack.hpp index 99df3887..64ce13b0 100644 --- a/pv/data/decoderstack.hpp +++ b/pv/data/decoderstack.hpp @@ -37,6 +37,7 @@ #include #include +#include struct srd_decoder; struct srd_decoder_annotation_row; @@ -89,7 +90,7 @@ public: double samplerate() const; - double start_time() const; + const pv::util::Timestamp& start_time() const; int64_t samples_decoded() const; @@ -135,7 +136,7 @@ Q_SIGNALS: private: pv::Session &session_; - double start_time_; + pv::util::Timestamp start_time_; double samplerate_; /** diff --git a/pv/data/segment.cpp b/pv/data/segment.cpp index bc08fd07..831c0aca 100644 --- a/pv/data/segment.cpp +++ b/pv/data/segment.cpp @@ -52,7 +52,7 @@ uint64_t Segment::get_sample_count() const return sample_count_; } -double Segment::start_time() const +const pv::util::Timestamp& Segment::start_time() const { return start_time_; } diff --git a/pv/data/segment.hpp b/pv/data/segment.hpp index 97dd4723..5d0a242a 100644 --- a/pv/data/segment.hpp +++ b/pv/data/segment.hpp @@ -21,6 +21,8 @@ #ifndef PULSEVIEW_PV_DATA_SEGMENT_HPP #define PULSEVIEW_PV_DATA_SEGMENT_HPP +#include "pv/util.hpp" + #include #include #include @@ -37,7 +39,7 @@ public: uint64_t get_sample_count() const; - double start_time() const; + const pv::util::Timestamp& start_time() const; double samplerate() const; void set_samplerate(double samplerate); @@ -78,7 +80,7 @@ protected: mutable std::recursive_mutex mutex_; std::vector data_; uint64_t sample_count_; - double start_time_; + pv::util::Timestamp start_time_; double samplerate_; uint64_t capacity_; unsigned int unit_size_; diff --git a/pv/toolbars/mainbar.cpp b/pv/toolbars/mainbar.cpp index de476e04..fff245d3 100644 --- a/pv/toolbars/mainbar.cpp +++ b/pv/toolbars/mainbar.cpp @@ -584,7 +584,7 @@ bool MainBar::eventFilter(QObject *watched, QEvent *event) { if ((watched == &sample_count_ || watched == &sample_rate_) && (event->type() == QEvent::ToolTip)) { - double sec = (double)sample_count_.value() / sample_rate_.value(); + auto sec = pv::util::Timestamp(sample_count_.value()) / sample_rate_.value(); QHelpEvent *help_event = static_cast(event); QString str = tr("Total sampling time: %1").arg(pv::util::format_second(sec)); diff --git a/pv/util.cpp b/pv/util.cpp index d2d70827..192a2e06 100644 --- a/pv/util.cpp +++ b/pv/util.cpp @@ -41,7 +41,7 @@ const int FirstSIPrefix = 8; const int FirstSIPrefixPower = -(FirstSIPrefix * 3); const double MinTimeDelta = 1e-15; // Anything below 1 fs can be considered zero -QString format_si_value(double v, QString unit, int prefix, +static QString format_si_value(double v, QString unit, int prefix, unsigned int precision, bool sign) { if (prefix < 0) { @@ -71,6 +71,12 @@ QString format_si_value(double v, QString unit, int prefix, return s; } +QString format_si_value(const Timestamp& v, QString unit, int prefix, + unsigned int precision, bool sign) +{ + return format_si_value(v.convert_to(), unit, prefix, precision, sign); +} + static QString pad_number(unsigned int number, int length) { return QString("%1").arg(number, length, 10, QChar('0')); @@ -156,7 +162,7 @@ static QString format_time_with_si(double t, QString unit, int prefix, return format_si_value(t, unit, prefix, relative_prec); } -QString format_time(double t, int prefix, TimeUnit unit, unsigned int precision) +static QString format_time(double t, int prefix, TimeUnit unit, unsigned int precision) { // Make 0 appear as 0, not random +0 or -0 if (fabs(t) < MinTimeDelta) @@ -176,9 +182,14 @@ QString format_time(double t, int prefix, TimeUnit unit, unsigned int precision) return format_time_in_full(t, precision); } -QString format_second(double second) +QString format_time(const Timestamp& t, int prefix, TimeUnit unit, unsigned int precision) +{ + return format_time(t.convert_to(), prefix, unit, precision); +} + +QString format_second(const Timestamp& second) { - return format_si_value(second, "s", -1, 0, false); + return format_si_value(second.convert_to(), "s", -1, 0, false); } } // namespace util diff --git a/pv/util.hpp b/pv/util.hpp index d59ad10e..b1e45dfb 100644 --- a/pv/util.hpp +++ b/pv/util.hpp @@ -23,6 +23,8 @@ #include +#include + #include namespace pv { @@ -33,35 +35,41 @@ enum TimeUnit { Samples = 2 }; +/// Timestamp type providing yoctosecond resolution. +typedef boost::multiprecision::number< + boost::multiprecision::cpp_dec_float<24>, + boost::multiprecision::et_off> Timestamp; + extern const int FirstSIPrefixPower; /** * Formats a given value with the specified SI prefix. * @param v The value to format. * @param unit The unit of quantity. - * @param prefix The number of the prefix, from 0 for 'femto' up to - * 8 for 'giga'. If prefix is set to -1, the prefix will be calculated. + * @param prefix The number of the prefix, from 0 for 'yotta' up to + * 16 for 'yokto'. If prefix is set to -1, the prefix will be calculated. * @param precision The number of digits after the decimal separator. * @param sign Whether or not to add a sign also for positive numbers. * * @return The formated value. */ QString format_si_value( - double v, QString unit, int prefix = -1, + const Timestamp& v, QString unit, int prefix = -1, unsigned precision = 0, bool sign = true); /** * Formats a given time with the specified SI prefix. * @param t The time value in seconds to format. - * @param prefix The number of the prefix, from 0 for 'femto' up to - * 8 for 'giga'. If prefix is set to -1, the prefix will be calculated. + * @param prefix The number of the prefix, from 0 for 'yotta' up to + * 16 for 'yokto'. If prefix is set to -1, the prefix will be calculated. * @param unit The unit of quantity. * @param precision The number of digits after the decimal separator or period (.). * * @return The formated value. */ QString format_time( - double t, int prefix = -1, TimeUnit unit = Time, unsigned precision = 0); + const Timestamp& t, int prefix = -1, + TimeUnit unit = Time, unsigned precision = 0); /** * Formats a given time value with a SI prefix so that the @@ -70,7 +78,7 @@ QString format_time( * * @return The formated value. */ -QString format_second(double second); +QString format_second(const Timestamp& second); } // namespace util } // namespace pv diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index 0ac63111..8e541dac 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -113,15 +113,15 @@ void AnalogSignal::paint_mid(QPainter &p, const ViewItemPaintParams &pp) const double pixels_offset = pp.pixels_offset(); const double samplerate = segment->samplerate(); - const double start_time = segment->start_time(); + const pv::util::Timestamp& start_time = segment->start_time(); const int64_t last_sample = segment->get_sample_count() - 1; const double samples_per_pixel = samplerate * pp.scale(); - const double start = samplerate * (pp.offset() - start_time); - const double end = start + samples_per_pixel * pp.width(); + const pv::util::Timestamp start = samplerate * (pp.offset() - start_time); + const pv::util::Timestamp end = start + samples_per_pixel * pp.width(); - const int64_t start_sample = min(max((int64_t)floor(start), + const int64_t start_sample = min(max(floor(start).convert_to(), (int64_t)0), last_sample); - const int64_t end_sample = min(max((int64_t)ceil(end) + 1, + const int64_t end_sample = min(max((ceil(end) + 1).convert_to(), (int64_t)0), last_sample); if (samples_per_pixel < EnvelopeThreshold) diff --git a/pv/view/cursor.cpp b/pv/view/cursor.cpp index 2f2bc482..e4704be4 100644 --- a/pv/view/cursor.cpp +++ b/pv/view/cursor.cpp @@ -64,7 +64,7 @@ QRectF Cursor::label_rect(const QRectF &rect) const const shared_ptr other(get_other_cursor()); assert(other); - const float x = (time_ - view_.offset()) / view_.scale(); + const float x = ((time_ - view_.offset())/ view_.scale()).convert_to(); QFontMetrics m(QApplication::font()); QSize text_size = m.boundingRect(get_text()).size(); @@ -76,14 +76,13 @@ QRectF Cursor::label_rect(const QRectF &rect) const TimeMarker::ArrowSize - 0.5f; const float height = label_size.height(); - const double other_time = other->time(); + const pv::util::Timestamp& other_time = other->time(); + if (time_ > other_time || - (abs(time_ - other_time) < numeric_limits::epsilon() && - this > other.get())) + (abs(time_ - other_time).is_zero() && this > other.get())) return QRectF(x, top, label_size.width(), height); else - return QRectF(x - label_size.width(), top, - label_size.width(), height); + return QRectF(x - label_size.width(), top, label_size.width(), height); } shared_ptr Cursor::get_other_cursor() const diff --git a/pv/view/cursorpair.cpp b/pv/view/cursorpair.cpp index d7723752..7b9f671f 100644 --- a/pv/view/cursorpair.cpp +++ b/pv/view/cursorpair.cpp @@ -60,8 +60,8 @@ shared_ptr CursorPair::second() const return second_; } -void CursorPair::set_time(double time) { - const double delta = second_->time() - first_->time(); +void CursorPair::set_time(const pv::util::Timestamp& time) { + const pv::util::Timestamp delta = second_->time() - first_->time(); first_->set_time(time); second_->set_time(time + delta); } @@ -162,7 +162,7 @@ void CursorPair::paint_back(QPainter &p, const ViewItemPaintParams &pp) { QString CursorPair::format_string() { const unsigned int prefix = view_.tick_prefix(); - const double delta = second_->time() - first_->time(); + const pv::util::Timestamp delta = second_->time() - first_->time(); return QString("%1 / %2"). arg(util::format_time(delta, prefix, view_.time_unit(), 2)). arg(util::format_si_value(1.0 / fabs(delta), "Hz", -1, 4)); @@ -182,8 +182,8 @@ pair CursorPair::get_cursor_offsets() const assert(second_); return pair( - (first_->time() - view_.offset()) / view_.scale(), - (second_->time() - view_.offset()) / view_.scale()); + ((first_->time() - view_.offset()) / view_.scale()).convert_to(), + ((second_->time() - view_.offset()) / view_.scale()).convert_to()); } } // namespace view diff --git a/pv/view/cursorpair.hpp b/pv/view/cursorpair.hpp index af7e67dc..2d47212e 100644 --- a/pv/view/cursorpair.hpp +++ b/pv/view/cursorpair.hpp @@ -64,7 +64,7 @@ public: /** * Sets the time of the marker. */ - void set_time(double time); + void set_time(const pv::util::Timestamp& time) override; float get_x() const; diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp index 7bb62b2b..c0c4d167 100644 --- a/pv/view/decodetrace.cpp +++ b/pv/view/decodetrace.cpp @@ -525,7 +525,7 @@ pair DecodeTrace::get_pixels_offset_samples_per_pixel() const assert(scale > 0); const double pixels_offset = - (view->offset() - decoder_stack_->start_time()) / scale; + ((view->offset() - decoder_stack_->start_time()) / scale).convert_to(); double samplerate = decoder_stack_->samplerate(); diff --git a/pv/view/flag.cpp b/pv/view/flag.cpp index 1dc38a57..779ea2ee 100644 --- a/pv/view/flag.cpp +++ b/pv/view/flag.cpp @@ -37,7 +37,7 @@ namespace view { const QColor Flag::FillColour(0x73, 0xD2, 0x16); -Flag::Flag(View &view, double time, const QString &text) : +Flag::Flag(View &view, const pv::util::Timestamp& time, const QString &text) : TimeMarker(view, FillColour, time), text_(text) { diff --git a/pv/view/flag.hpp b/pv/view/flag.hpp index 26562102..bc82934e 100644 --- a/pv/view/flag.hpp +++ b/pv/view/flag.hpp @@ -45,7 +45,7 @@ public: * @param time The time to set the flag to. * @param text The text of the marker. */ - Flag(View &view, double time, const QString &text); + Flag(View &view, const pv::util::Timestamp& time, const QString &text); /** * Copy constructor. diff --git a/pv/view/logicsignal.cpp b/pv/view/logicsignal.cpp index 49d12636..b20e5f06 100644 --- a/pv/view/logicsignal.cpp +++ b/pv/view/logicsignal.cpp @@ -189,15 +189,18 @@ void LogicSignal::paint_mid(QPainter &p, const ViewItemPaintParams &pp) samplerate = 1.0; const double pixels_offset = pp.pixels_offset(); - const double start_time = segment->start_time(); + const pv::util::Timestamp& start_time = segment->start_time(); const int64_t last_sample = segment->get_sample_count() - 1; const double samples_per_pixel = samplerate * pp.scale(); - const double start = samplerate * (pp.offset() - start_time); - const double end = start + samples_per_pixel * pp.width(); + const pv::util::Timestamp start = samplerate * (pp.offset() - start_time); + const pv::util::Timestamp end = start + samples_per_pixel * pp.width(); - segment->get_subsampled_edges(edges, - min(max((int64_t)floor(start), (int64_t)0), last_sample), - min(max((int64_t)ceil(end), (int64_t)0), last_sample), + const int64_t start_sample = min(max(floor(start).convert_to(), + (int64_t)0), last_sample); + const uint64_t end_sample = min(max(ceil(end).convert_to(), + (int64_t)0), last_sample); + + segment->get_subsampled_edges(edges, start_sample, end_sample, samples_per_pixel / Oversampling, channel_->index()); assert(edges.size() >= 2); diff --git a/pv/view/ruler.cpp b/pv/view/ruler.cpp index dfe7d1c5..2cd12753 100644 --- a/pv/view/ruler.cpp +++ b/pv/view/ruler.cpp @@ -97,9 +97,9 @@ void Ruler::paintEvent(QPaintEvent*) const double minor_tick_period = tick_period / MinorTickSubdivision; const double first_major_division = - floor(view_.offset() / tick_period); + floor(view_.offset() / tick_period).convert_to(); const double first_minor_division = - ceil(view_.offset() / minor_tick_period); + ceil(view_.offset() / minor_tick_period).convert_to(); const double t0 = first_major_division * tick_period; int division = (int)round(first_minor_division - @@ -114,7 +114,7 @@ void Ruler::paintEvent(QPaintEvent*) do { const double t = t0 + division * minor_tick_period; - x = (t - view_.offset()) / view_.scale(); + x = ((t - view_.offset()) / view_.scale()).convert_to(); if (division % MinorTickSubdivision == 0) { diff --git a/pv/view/timeitem.hpp b/pv/view/timeitem.hpp index 4cb650d9..cd6f5f24 100644 --- a/pv/view/timeitem.hpp +++ b/pv/view/timeitem.hpp @@ -44,7 +44,7 @@ public: /** * Sets the time of the marker. */ - virtual void set_time(double time) = 0; + virtual void set_time(const pv::util::Timestamp& time) = 0; virtual float get_x() const = 0; diff --git a/pv/view/timemarker.cpp b/pv/view/timemarker.cpp index e4ef3c0e..f1424627 100644 --- a/pv/view/timemarker.cpp +++ b/pv/view/timemarker.cpp @@ -41,7 +41,8 @@ namespace view { const int TimeMarker::ArrowSize = 4; -TimeMarker::TimeMarker(View &view, const QColor &colour, double time) : +TimeMarker::TimeMarker( + View &view, const QColor &colour, const pv::util::Timestamp& time) : TimeItem(view), colour_(colour), time_(time), @@ -51,18 +52,18 @@ TimeMarker::TimeMarker(View &view, const QColor &colour, double time) : { } -double TimeMarker::time() const +const pv::util::Timestamp& TimeMarker::time() const { return time_; } -void TimeMarker::set_time(double time) +void TimeMarker::set_time(const pv::util::Timestamp& time) { time_ = time; if (value_widget_) { updating_value_widget_ = true; - value_widget_->setValue(time); + value_widget_->setValue(time.convert_to()); updating_value_widget_ = false; } @@ -71,7 +72,7 @@ void TimeMarker::set_time(double time) float TimeMarker::get_x() const { - return (time_ - view_.offset()) / view_.scale(); + return ((time_ - view_.offset()) / view_.scale()).convert_to(); } QPoint TimeMarker::point(const QRect &rect) const @@ -105,7 +106,7 @@ void TimeMarker::paint_label(QPainter &p, const QRect &rect, bool hover) if (!enabled()) return; - const qreal x = (time_ - view_.offset()) / view_.scale(); + const qreal x = ((time_ - view_.offset()) / view_.scale()).convert_to(); const QRectF r(label_rect(rect)); const QPointF points[] = { @@ -177,7 +178,7 @@ pv::widgets::Popup* TimeMarker::create_popup(QWidget *parent) value_widget_->setSuffix("s"); value_widget_->setSingleStep(1e-6); value_widget_->setRange(-1.0e9, 1.0e9); - value_widget_->setValue(time_); + value_widget_->setValue(time_.convert_to()); connect(value_widget_, SIGNAL(valueChanged(double)), this, SLOT(on_value_changed(double))); diff --git a/pv/view/timemarker.hpp b/pv/view/timemarker.hpp index c72dedf5..10e3331c 100644 --- a/pv/view/timemarker.hpp +++ b/pv/view/timemarker.hpp @@ -51,18 +51,18 @@ protected: * @param colour A reference to the colour of this cursor. * @param time The time to set the flag to. */ - TimeMarker(View &view, const QColor &colour, double time); + TimeMarker(View &view, const QColor &colour, const pv::util::Timestamp& time); public: /** * Gets the time of the marker. */ - double time() const; + const pv::util::Timestamp& time() const; /** * Sets the time of the marker. */ - void set_time(double time); + void set_time(const pv::util::Timestamp& time) override; float get_x() const; @@ -114,7 +114,7 @@ private Q_SLOTS: protected: const QColor &colour_; - double time_; + pv::util::Timestamp time_; QSizeF text_size_; diff --git a/pv/view/view.cpp b/pv/view/view.cpp index 12c277d5..652c4f80 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -62,6 +62,7 @@ using pv::data::SignalData; using pv::data::Segment; using pv::util::format_time; using pv::util::TimeUnit; +using pv::util::Timestamp; using std::deque; using std::dynamic_pointer_cast; @@ -83,8 +84,8 @@ using std::weak_ptr; namespace pv { namespace view { -const double View::MaxScale = 1e9; -const double View::MinScale = 1e-12; +const Timestamp View::MaxScale("1e9"); +const Timestamp View::MinScale("1e-12"); const int View::MaxScrollValue = INT_MAX / 2; const int View::MaxViewAutoUpdateRate = 25; // No more than 25 Hz with sticky scrolling @@ -210,7 +211,7 @@ double View::scale() const return scale_; } -double View::offset() const +const Timestamp& View::offset() const { return offset_; } @@ -273,9 +274,9 @@ void View::zoom_fit(bool gui_state) always_zoom_to_fit_changed(gui_state); } - const pair extents = get_time_extents(); - const double delta = extents.second - extents.first; - if (delta < 1e-12) + const pair extents = get_time_extents(); + const Timestamp delta = extents.second - extents.first; + if (delta < Timestamp("1e-12")) return; assert(viewport_); @@ -283,8 +284,8 @@ void View::zoom_fit(bool gui_state) if (w <= 0) return; - const double scale = max(min(delta / w, MaxScale), MinScale); - set_scale_offset(scale, extents.first); + const Timestamp scale = max(min(delta / w, MaxScale), MinScale); + set_scale_offset(scale.convert_to(), extents.first); } void View::zoom_one_to_one() @@ -316,7 +317,7 @@ void View::zoom_one_to_one() set_zoom(1.0 / samplerate, w / 2); } -void View::set_scale_offset(double scale, double offset) +void View::set_scale_offset(double scale, const Timestamp& offset) { // Disable sticky scrolling / always zoom to fit when acquisition runs // and user drags the viewport @@ -359,9 +360,9 @@ set< shared_ptr > View::get_visible_data() const return visible_data; } -pair View::get_time_extents() const +pair View::get_time_extents() const { - double left_time = DBL_MAX, right_time = DBL_MIN; + boost::optional left_time, right_time; const set< shared_ptr > visible_data = get_visible_data(); for (const shared_ptr d : visible_data) { @@ -371,18 +372,21 @@ pair View::get_time_extents() const double samplerate = s->samplerate(); samplerate = (samplerate <= 0.0) ? 1.0 : samplerate; - const double start_time = s->start_time(); - left_time = min(left_time, start_time); - right_time = max(right_time, start_time + - d->max_sample_count() / samplerate); + const Timestamp start_time = s->start_time(); + left_time = left_time ? + min(*left_time, start_time) : + start_time; + right_time = right_time ? + max(*right_time, start_time + d->max_sample_count() / samplerate) : + start_time + d->max_sample_count() / samplerate; } } - if (left_time == DBL_MAX && right_time == DBL_MIN) - return make_pair(0.0, 0.0); + if (!left_time || !right_time) + return make_pair(0, 0); - assert(left_time < right_time); - return make_pair(left_time, right_time); + assert(*left_time < *right_time); + return make_pair(*left_time, *right_time); } void View::enable_sticky_scrolling(bool state) @@ -416,7 +420,7 @@ std::shared_ptr View::cursors() const return cursors_; } -void View::add_flag(double time) +void View::add_flag(const Timestamp& time) { flags_.push_back(shared_ptr(new Flag(*this, time, QString("%1").arg(next_flag_text_)))); @@ -472,10 +476,10 @@ void View::restack_all_row_items() r->animate_to_layout_v_offset(); } -void View::get_scroll_layout(double &length, double &offset) const +void View::get_scroll_layout(double &length, Timestamp &offset) const { - const pair extents = get_time_extents(); - length = (extents.second - extents.first) / scale_; + const pair extents = get_time_extents(); + length = ((extents.second - extents.first) / scale_).convert_to(); offset = offset_ / scale_; } @@ -485,10 +489,10 @@ void View::set_zoom(double scale, int offset) always_zoom_to_fit_ = false; always_zoom_to_fit_changed(false); - const double cursor_offset = offset_ + scale_ * offset; - const double new_scale = max(min(scale, MaxScale), MinScale); - const double new_offset = cursor_offset - new_scale * offset; - set_scale_offset(new_scale, new_offset); + const Timestamp cursor_offset = offset_ + scale_ * offset; + const Timestamp new_scale = max(min(Timestamp(scale), MaxScale), MinScale); + const Timestamp new_offset = cursor_offset - new_scale * offset; + set_scale_offset(new_scale.convert_to(), new_offset); } void View::calculate_tick_spacing() @@ -498,7 +502,7 @@ void View::calculate_tick_spacing() // Figure out the highest numeric value visible on a label const QSize areaSize = viewport_->size(); - const double max_time = max(fabs(offset_), + const Timestamp max_time = max(fabs(offset_), fabs(offset_ + scale_ * areaSize.width())); double min_width = SpacingIncrement; @@ -552,7 +556,8 @@ void View::update_scroll() const QSize areaSize = viewport_->size(); // Set the horizontal scroll bar - double length = 0, offset = 0; + double length = 0; + Timestamp offset; get_scroll_layout(length, offset); length = max(length - areaSize.width(), 0.0); @@ -565,11 +570,11 @@ void View::update_scroll() if (length < MaxScrollValue) { horizontalScrollBar()->setRange(0, length); - horizontalScrollBar()->setSliderPosition(offset); + horizontalScrollBar()->setSliderPosition(offset.convert_to()); } else { horizontalScrollBar()->setRange(0, MaxScrollValue); horizontalScrollBar()->setSliderPosition( - offset_ * MaxScrollValue / (scale_ * length)); + (offset_ * MaxScrollValue / (scale_ * length)).convert_to()); } updating_scroll_ = false; @@ -782,7 +787,8 @@ void View::h_scroll_value_changed(int value) if (range < MaxScrollValue) offset_ = scale_ * value; else { - double length = 0, offset; + double length = 0; + Timestamp offset; get_scroll_layout(length, offset); offset_ = scale_ * length * value / MaxScrollValue; } @@ -961,7 +967,8 @@ void View::perform_delayed_view_update() if (sticky_scrolling_) { // Make right side of the view sticky - double length = 0, offset; + double length = 0; + Timestamp offset; get_scroll_layout(length, offset); const QSize areaSize = viewport_->size(); diff --git a/pv/view/view.hpp b/pv/view/view.hpp index ff7795c5..12527b65 100644 --- a/pv/view/view.hpp +++ b/pv/view/view.hpp @@ -66,8 +66,8 @@ private: }; private: - static const double MaxScale; - static const double MinScale; + static const pv::util::Timestamp MaxScale; + static const pv::util::Timestamp MinScale; static const int MaxScrollValue; static const int MaxViewAutoUpdateRate; @@ -108,7 +108,7 @@ public: * Returns the time offset of the left edge of the view in * seconds. */ - double offset() const; + const pv::util::Timestamp& offset() const; /** * Returns the vertical scroll offset. @@ -157,12 +157,12 @@ public: * @param scale The new view scale in seconds per pixel. * @param offset The view time offset in seconds. */ - void set_scale_offset(double scale, double offset); + void set_scale_offset(double scale, const pv::util::Timestamp& offset); std::set< std::shared_ptr > get_visible_data() const; - std::pair get_time_extents() const; + std::pair get_time_extents() const; /** * Enables or disables sticky scrolling, i.e. the view always shows @@ -193,7 +193,7 @@ public: /** * Adds a new flag at a specified time. */ - void add_flag(double time); + void add_flag(const pv::util::Timestamp& time); /** * Removes a flag from the list. @@ -223,7 +223,7 @@ Q_SIGNALS: void always_zoom_to_fit_changed(bool state); private: - void get_scroll_layout(double &length, double &offset) const; + void get_scroll_layout(double &length, pv::util::Timestamp &offset) const; /** * Simultaneously sets the zoom and offset. @@ -311,7 +311,7 @@ private: double scale_; /// The view time offset in seconds. - double offset_; + pv::util::Timestamp offset_; bool updating_scroll_; bool sticky_scrolling_; diff --git a/pv/view/viewitempaintparams.cpp b/pv/view/viewitempaintparams.cpp index 83dda4e5..db44f48f 100644 --- a/pv/view/viewitempaintparams.cpp +++ b/pv/view/viewitempaintparams.cpp @@ -29,7 +29,7 @@ namespace pv { namespace view { ViewItemPaintParams::ViewItemPaintParams( - const QRect &rect, double scale, double offset) : + const QRect &rect, double scale, const pv::util::Timestamp& offset) : rect_(rect), scale_(scale), offset_(offset) { diff --git a/pv/view/viewitempaintparams.hpp b/pv/view/viewitempaintparams.hpp index 86742ba7..460bd6c9 100644 --- a/pv/view/viewitempaintparams.hpp +++ b/pv/view/viewitempaintparams.hpp @@ -21,6 +21,8 @@ #ifndef PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_HPP #define PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_HPP +#include "pv/util.hpp" + #include namespace pv { @@ -29,7 +31,8 @@ namespace view { class ViewItemPaintParams { public: - ViewItemPaintParams(const QRect &rect, double scale, double offset); + ViewItemPaintParams( + const QRect &rect, double scale, const pv::util::Timestamp& offset); QRect rect() const { return rect_; @@ -39,7 +42,7 @@ public: return scale_; } - double offset() const { + const pv::util::Timestamp& offset() const { return offset_; } @@ -68,7 +71,7 @@ public: } double pixels_offset() const { - return offset_ / scale_; + return (offset_ / scale_).convert_to(); } public: @@ -79,7 +82,7 @@ public: private: QRect rect_; double scale_; - double offset_; + pv::util::Timestamp offset_; }; } // namespace view diff --git a/pv/view/viewport.cpp b/pv/view/viewport.cpp index d9be32c9..d555a792 100644 --- a/pv/view/viewport.cpp +++ b/pv/view/viewport.cpp @@ -49,7 +49,6 @@ namespace view { Viewport::Viewport(View &parent) : ViewWidget(parent), - drag_offset_(numeric_limits::signaling_NaN()), pinch_zoom_active_(false) { setAutoFillBackground(true); @@ -82,17 +81,16 @@ void Viewport::drag() void Viewport::drag_by(const QPoint &delta) { - // Use std::isnan() instead of isnan(), the latter can cause issues. - if (std::isnan(drag_offset_)) + if (drag_offset_ == boost::none) return; - view_.set_scale_offset(view_.scale(), drag_offset_ - - delta.x() * view_.scale()); + view_.set_scale_offset(view_.scale(), + (*drag_offset_ - delta.x() * view_.scale())); } void Viewport::drag_release() { - drag_offset_ = numeric_limits::signaling_NaN(); + drag_offset_ = boost::none; } vector< shared_ptr > Viewport::items() @@ -117,8 +115,8 @@ bool Viewport::touch_event(QTouchEvent *event) if (!pinch_zoom_active_ || (event->touchPointStates() & Qt::TouchPointPressed)) { - pinch_offset0_ = view_.offset() + view_.scale() * touchPoint0.pos().x(); - pinch_offset1_ = view_.offset() + view_.scale() * touchPoint1.pos().x(); + pinch_offset0_ = (view_.offset() + view_.scale() * touchPoint0.pos().x()).convert_to(); + pinch_offset1_ = (view_.offset() + view_.scale() * touchPoint1.pos().x()).convert_to(); pinch_zoom_active_ = true; } diff --git a/pv/view/viewport.hpp b/pv/view/viewport.hpp index 2c8211b8..c2c42d15 100644 --- a/pv/view/viewport.hpp +++ b/pv/view/viewport.hpp @@ -21,9 +21,12 @@ #ifndef PULSEVIEW_PV_VIEW_VIEWPORT_HPP #define PULSEVIEW_PV_VIEW_VIEWPORT_HPP +#include + #include #include +#include "pv/util.hpp" #include "viewwidget.hpp" class QPainter; @@ -93,7 +96,7 @@ private: void wheelEvent(QWheelEvent *event); private: - double drag_offset_; + boost::optional drag_offset_; double pinch_offset0_; double pinch_offset1_;