]> sigrok.org Git - pulseview.git/commitdiff
Use a type with a greater resolution to represent time values
authorJens Steinhauser <redacted>
Sun, 30 Aug 2015 21:00:34 +0000 (23:00 +0200)
committerUwe Hermann <redacted>
Fri, 4 Sep 2015 10:54:51 +0000 (12:54 +0200)
Fixes #627.

25 files changed:
pv/data/decoderstack.cpp
pv/data/decoderstack.hpp
pv/data/segment.cpp
pv/data/segment.hpp
pv/toolbars/mainbar.cpp
pv/util.cpp
pv/util.hpp
pv/view/analogsignal.cpp
pv/view/cursor.cpp
pv/view/cursorpair.cpp
pv/view/cursorpair.hpp
pv/view/decodetrace.cpp
pv/view/flag.cpp
pv/view/flag.hpp
pv/view/logicsignal.cpp
pv/view/ruler.cpp
pv/view/timeitem.hpp
pv/view/timemarker.cpp
pv/view/timemarker.hpp
pv/view/view.cpp
pv/view/view.hpp
pv/view/viewitempaintparams.cpp
pv/view/viewitempaintparams.hpp
pv/view/viewport.cpp
pv/view/viewport.hpp

index ef497f72bb29e2e80eaba88676340c6d499949d7..0bb875da74b68e8a30086e90124d69eea93400b5 100644 (file)
@@ -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_;
 }
index 99df3887ce422a5a88f718d5c223c108023f65e3..64ce13b01253398850cfa99a9921074090507980 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <pv/data/decode/row.hpp>
 #include <pv/data/decode/rowdata.hpp>
+#include <pv/util.hpp>
 
 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_;
 
        /**
index bc08fd07917564d86e13f35f3d37ad20dcae64e9..831c0acaac49cf68fd428ce7ef57fabc6f8a4576 100644 (file)
@@ -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_;
 }
index 97dd47237cbe65aa28db8a87d8d6f4eaa323397b..5d0a242aaf00f0634339eb25eb9f48644381f3e5 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef PULSEVIEW_PV_DATA_SEGMENT_HPP
 #define PULSEVIEW_PV_DATA_SEGMENT_HPP
 
+#include "pv/util.hpp"
+
 #include <thread>
 #include <mutex>
 #include <vector>
@@ -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<uint8_t> data_;
        uint64_t sample_count_;
-       double start_time_;
+       pv::util::Timestamp start_time_;
        double samplerate_;
        uint64_t capacity_;
        unsigned int unit_size_;
index de476e04c94444eaf58c0d3317297efc7b3a5ea3..fff245d31e8d44b3b3986480f339c44a031b7ce9 100644 (file)
@@ -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<QHelpEvent*>(event);
 
                QString str = tr("Total sampling time: %1").arg(pv::util::format_second(sec));
index d2d70827335d0fb86cbeb0b0a2cd160ebc33569b..192a2e06ba1571766bbab637e1135d1980b5904a 100644 (file)
@@ -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<double>(), 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<double>(), 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<double>(), "s", -1, 0, false);
 }
 
 } // namespace util
index d59ad10eb804831f08c1b817bc4dd2deacdfc7ed..b1e45dfb6a716d18d1d1ebf10014cb2c498314cb 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <cmath>
 
+#include <boost/multiprecision/cpp_dec_float.hpp>
+
 #include <QString>
 
 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
index 0ac6311116610356b12f0663fa0fc933539f801e..8e541dac1672da902233105215f49d0c4c271c01 100644 (file)
@@ -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>(),
                (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>(),
                (int64_t)0), last_sample);
 
        if (samples_per_pixel < EnvelopeThreshold)
index 2f2bc482f22cc567c408723cd6eb8eedd651df32..e4704be497500fd3323ef254ca2dc6c35086d06f 100644 (file)
@@ -64,7 +64,7 @@ QRectF Cursor::label_rect(const QRectF &rect) const
        const shared_ptr<Cursor> other(get_other_cursor());
        assert(other);
 
-       const float x = (time_ - view_.offset()) / view_.scale();
+       const float x = ((time_ - view_.offset())/ view_.scale()).convert_to<float>();
 
        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<double>::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> Cursor::get_other_cursor() const
index d7723752b62e6952467ef5ec5c615df4f049c364..7b9f671f036f603809ec420d172cde2198d7f479 100644 (file)
@@ -60,8 +60,8 @@ shared_ptr<Cursor> 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<float, float> CursorPair::get_cursor_offsets() const
        assert(second_);
 
        return pair<float, float>(
-               (first_->time() - view_.offset()) / view_.scale(),
-               (second_->time() - view_.offset()) / view_.scale());
+               ((first_->time() - view_.offset()) / view_.scale()).convert_to<float>(),
+               ((second_->time() - view_.offset()) / view_.scale()).convert_to<float>());
 }
 
 } // namespace view
index af7e67dc0b16788ba7725235d14219f1649c6f24..2d47212ef77f1879ff3e7e9b0c761d609b33394c 100644 (file)
@@ -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;
 
index 7bb62b2b288703c69dc9f725fad7cd43e071daf5..c0c4d167e109f17f16eeb374aba8420d863dd86f 100644 (file)
@@ -525,7 +525,7 @@ pair<double, double> 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>();
 
        double samplerate = decoder_stack_->samplerate();
 
index 1dc38a5741b0cafd357b6c965caa504217fae707..779ea2eec24cd8d5088b2675f9ede6978c682ba1 100644 (file)
@@ -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)
 {
index 265621029d3ec99797a26f465abc893b55659c2d..bc82934e161e5829d5d025f515931c5817a60268 100644 (file)
@@ -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.
index 49d1263642b9b97ee3bac15c95fbe8a897e2f724..b20e5f06bf457b2b7710085aa39addbe0cab3757 100644 (file)
@@ -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>(),
+               (int64_t)0), last_sample);
+       const uint64_t end_sample = min(max(ceil(end).convert_to<int64_t>(),
+               (int64_t)0), last_sample);
+
+       segment->get_subsampled_edges(edges, start_sample, end_sample,
                samples_per_pixel / Oversampling, channel_->index());
        assert(edges.size() >= 2);
 
index dfe7d1c555161d6d1d9ca589bfca099695cfc5ab..2cd1275348d737f9f2f3c6fd1868c977118fe7aa 100644 (file)
@@ -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<double>();
        const double first_minor_division =
-               ceil(view_.offset() / minor_tick_period);
+               ceil(view_.offset() / minor_tick_period).convert_to<double>();
        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<double>();
 
                if (division % MinorTickSubdivision == 0)
                {
index 4cb650d961adb8ea93610c47995b10c4b037c7f3..cd6f5f2499c428555189257482e118fd4ab57709 100644 (file)
@@ -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;
 
index e4ef3c0e1cb5edff4a2765484ca93a3697431369..f1424627d9aa27dae374175a5d11b4bf000e5f23 100644 (file)
@@ -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<double>());
                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<float>();
 }
 
 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<qreal>();
        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<double>());
 
        connect(value_widget_, SIGNAL(valueChanged(double)),
                this, SLOT(on_value_changed(double)));
index c72dedf56f79e0a1c223436e8841c8796337e125..10e3331c639ba4eee64bd146d1ea1d07c7fdd49c 100644 (file)
@@ -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_;
 
index 12c277d5434582a5e4b63ada3b85e4324154ff46..652c4f8087e637c32e1a94068b8dabdb6fbd6ab3 100644 (file)
@@ -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<double, double> extents = get_time_extents();
-       const double delta = extents.second - extents.first;
-       if (delta < 1e-12)
+       const pair<Timestamp, Timestamp> 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<double>(), 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<SignalData> > View::get_visible_data() const
        return visible_data;
 }
 
-pair<double, double> View::get_time_extents() const
+pair<Timestamp, Timestamp> View::get_time_extents() const
 {
-       double left_time = DBL_MAX, right_time = DBL_MIN;
+       boost::optional<Timestamp> left_time, right_time;
        const set< shared_ptr<SignalData> > visible_data = get_visible_data();
        for (const shared_ptr<SignalData> d : visible_data)
        {
@@ -371,18 +372,21 @@ pair<double, double> 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(00);
 
-       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<CursorPair> View::cursors() const
        return cursors_;
 }
 
-void View::add_flag(double time)
+void View::add_flag(const Timestamp& time)
 {
        flags_.push_back(shared_ptr<Flag>(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<double, double> extents = get_time_extents();
-       length = (extents.second - extents.first) / scale_;
+       const pair<Timestamp, Timestamp> extents = get_time_extents();
+       length = ((extents.second - extents.first) / scale_).convert_to<double>();
        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<double>(), 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<double>());
        } else {
                horizontalScrollBar()->setRange(0, MaxScrollValue);
                horizontalScrollBar()->setSliderPosition(
-                       offset_ * MaxScrollValue / (scale_ * length));
+                       (offset_ * MaxScrollValue / (scale_ * length)).convert_to<double>());
        }
 
        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();
index ff7795c5a68dbd55b92204d7236817e2dce35182..12527b656d80943f2abb8d69039d33729d45adc0 100644 (file)
@@ -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<pv::data::SignalData> >
                get_visible_data() const;
 
-       std::pair<double, double> get_time_extents() const;
+       std::pair<pv::util::Timestamp, pv::util::Timestamp> 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_;
index 83dda4e59e0a02bee325662655c08aa007a1a7bf..db44f48f308ee51c41e71c631b0435d8937bb7e5 100644 (file)
@@ -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) {
index 86742ba7ceb811ec1e3642f7ee15e1776ac1e36e..460bd6c94db8d33a263d433498158310ab273419 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_HPP
 #define PULSEVIEW_PV_VIEW_ROWITEMPAINTPARAMS_HPP
 
+#include "pv/util.hpp"
+
 #include <QFont>
 
 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<double>();
        }
 
 public:
@@ -79,7 +82,7 @@ public:
 private:
        QRect rect_;
        double scale_;
-       double offset_;
+       pv::util::Timestamp offset_;
 };
 
 } // namespace view
index d9be32c996ee142b44603d1c9097a9bcde93295a..d555a792ed5f1ad8a09093709919c1c25c75e48d 100644 (file)
@@ -49,7 +49,6 @@ namespace view {
 
 Viewport::Viewport(View &parent) :
        ViewWidget(parent),
-       drag_offset_(numeric_limits<double>::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<double>::signaling_NaN();
+       drag_offset_ = boost::none;
 }
 
 vector< shared_ptr<ViewItem> > 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<double>();
+               pinch_offset1_ = (view_.offset() + view_.scale() * touchPoint1.pos().x()).convert_to<double>();
                pinch_zoom_active_ = true;
        }
 
index 2c8211b8dce43b2cee22e8fb872ae7a64af15c2c..c2c42d155d79bf9ecbe28ed54b2741f37271b554 100644 (file)
 #ifndef PULSEVIEW_PV_VIEW_VIEWPORT_HPP
 #define PULSEVIEW_PV_VIEW_VIEWPORT_HPP
 
+#include <boost/optional.hpp>
+
 #include <QTimer>
 #include <QTouchEvent>
 
+#include "pv/util.hpp"
 #include "viewwidget.hpp"
 
 class QPainter;
@@ -93,7 +96,7 @@ private:
        void wheelEvent(QWheelEvent *event);
 
 private:
-       double drag_offset_;
+       boost::optional<pv::util::Timestamp> drag_offset_;
 
        double pinch_offset0_;
        double pinch_offset1_;