From 3ccf0f7f5b1b31ac628a983a2becee6f4c4c1507 Mon Sep 17 00:00:00 2001 From: Jens Steinhauser Date: Thu, 3 Sep 2015 13:50:53 +0200 Subject: [PATCH] Untangle the time formatting functions a bit The formatting depending on the distance between two timestamps is reintroduced with the responding function residing in the 'Ruler' class (the prime user of that function). Fixes a rounding bug for the least significant digit in the 'format_time_minutes()' function. The 'Cursor' and 'CursorPair' classes now use the same precision when formatting timestamps as the rest of the program. --- pv/toolbars/mainbar.cpp | 3 +- pv/util.cpp | 128 ++++++------- pv/util.hpp | 65 +++++-- pv/view/cursor.cpp | 8 +- pv/view/cursorpair.cpp | 13 +- pv/view/ruler.cpp | 35 +++- pv/view/ruler.hpp | 34 +++- pv/view/view.cpp | 5 +- pv/widgets/timestampspinbox.cpp | 4 +- test/util.cpp | 311 +++++++++++++++++--------------- test/view/ruler.cpp | 2 +- 11 files changed, 355 insertions(+), 253 deletions(-) diff --git a/pv/toolbars/mainbar.cpp b/pv/toolbars/mainbar.cpp index fff245d3..dcc35ece 100644 --- a/pv/toolbars/mainbar.cpp +++ b/pv/toolbars/mainbar.cpp @@ -587,7 +587,8 @@ bool MainBar::eventFilter(QObject *watched, QEvent *event) 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)); + QString str = tr("Total sampling time: %1").arg( + pv::util::format_time_si(sec, pv::util::SIPrefix::unspecified, 0, "s", false)); QToolTip::showText(help_event->globalPos(), str); return true; diff --git a/pv/util.cpp b/pv/util.cpp index 7bf6f434..4a32147d 100644 --- a/pv/util.cpp +++ b/pv/util.cpp @@ -110,8 +110,12 @@ static QTextStream& operator<<(QTextStream& stream, const Timestamp& t) return stream << QString::fromStdString(str); } -QString format_si_value(const Timestamp& v, QString unit, SIPrefix prefix, - unsigned int precision, bool sign) +QString format_time_si( + const Timestamp& v, + SIPrefix prefix, + unsigned int precision, + QString unit, + bool sign) { if (prefix == SIPrefix::unspecified) { // No prefix given, calculate it @@ -148,12 +152,32 @@ QString format_si_value(const Timestamp& v, QString unit, SIPrefix prefix, return s; } +QString format_time_si_adjusted( + const Timestamp& t, + SIPrefix prefix, + unsigned precision, + QString unit, + bool sign) +{ + // The precision is always given without taking the prefix into account + // so we need to deduct the number of decimals the prefix might imply + const int prefix_order = -exponent(prefix); + + const unsigned int relative_prec = + (prefix >= SIPrefix::none) ? precision : + std::max((int)(precision - prefix_order), 0); + + return format_time_si(t, prefix, relative_prec, unit, sign); +} + + +// Helper for 'format_time_minutes()'. static QString pad_number(unsigned int number, int length) { return QString("%1").arg(number, length, 10, QChar('0')); } -static QString format_time_in_full(const Timestamp& t, signed precision) +QString format_time_minutes(const Timestamp& t, signed precision, bool sign) { const Timestamp whole_seconds = floor(abs(t)); const Timestamp days = floor(whole_seconds / (60 * 60 * 24)); @@ -164,104 +188,58 @@ static QString format_time_in_full(const Timestamp& t, signed precision) QString s; QTextStream ts(&s); - if (t >= 0) - ts << "+"; - else + if (t < 0) ts << "-"; + else if (sign) + ts << "+"; bool use_padding = false; + // DD if (days) { ts << days.str().c_str() << ":"; use_padding = true; } + // HH if (hours || days) { ts << pad_number(hours, use_padding ? 2 : 0) << ":"; use_padding = true; } - if (minutes || hours || days) { - ts << pad_number(minutes, use_padding ? 2 : 0); - use_padding = true; + // MM + ts << pad_number(minutes, use_padding ? 2 : 0); - // We're not showing any seconds with a negative precision - if (precision >= 0) - ts << ":"; - } + ts << ":"; - // precision < 0: Use DD:HH:MM format - // precision = 0: Use DD:HH:MM:SS format - // precision > 0: Use DD:HH:MM:SS.mmm nnn ppp fff format - if (precision >= 0) { - ts << pad_number(seconds, use_padding ? 2 : 0); + // SS + ts << pad_number(seconds, 2); - const Timestamp fraction = fabs(t) - whole_seconds; + if (precision) { + ts << "."; - if (precision > 0 && precision < 1000) { - std::ostringstream ss; - ss - << std::fixed - << std::setprecision(2 + precision) - << std::setfill('0') - << fraction; - std::string fs = ss.str(); + const Timestamp fraction = fabs(t) - whole_seconds; - ts << "."; + std::ostringstream ss; + ss + << std::fixed + << std::setprecision(precision) + << std::setfill('0') + << fraction; + std::string fs = ss.str(); - // Copy all digits, inserting spaces as unit separators - for (int i = 1; i <= precision; i++) { - // Start at index 2 to skip the "0." at the beginning - ts << fs[1 + i]; + // Copy all digits, inserting spaces as unit separators + for (int i = 1; i <= precision; i++) { + // Start at index 2 to skip the "0." at the beginning + ts << fs.at(1 + i); - if ((i > 0) && (i % 3 == 0) && (i != precision)) - ts << " "; - } + if ((i > 0) && (i % 3 == 0) && (i != precision)) + ts << " "; } } return s; } -static QString format_time_with_si(const Timestamp& t, QString unit, - SIPrefix prefix, unsigned int precision) -{ - // The precision is always given without taking the prefix into account - // so we need to deduct the number of decimals the prefix might imply - const int prefix_order = -exponent(prefix); - - const unsigned int relative_prec = - (prefix >= SIPrefix::none) ? precision : - std::max((int)(precision - prefix_order), 0); - - return format_si_value(t, unit, prefix, relative_prec); -} - -QString format_time(const Timestamp& t, SIPrefix prefix, TimeUnit unit, - unsigned int precision) -{ - // Make 0 appear as 0, not random +0 or -0 - if (t.is_zero()) - return "0"; - - // If we have to use samples then we have no alternative formats - if (unit == TimeUnit::Samples) - return format_time_with_si(t, "sa", prefix, precision); - - // View in "normal" range -> medium precision, medium step size - // -> HH:MM:SS.mmm... or xxxx (si unit) if less than 60 seconds - // View zoomed way in -> high precision (>3), low step size (<1s) - // -> HH:MM:SS.mmm... or xxxx (si unit) if less than 60 seconds - if (abs(t) < 60) - return format_time_with_si(t, "s", prefix, precision); - else - return format_time_in_full(t, precision); -} - -QString format_second(const Timestamp& second) -{ - return format_si_value(second, "s", SIPrefix::unspecified, 0, false); -} - } // namespace util } // namespace pv diff --git a/pv/util.hpp b/pv/util.hpp index f2740d40..5be37903 100644 --- a/pv/util.hpp +++ b/pv/util.hpp @@ -56,40 +56,69 @@ typedef boost::multiprecision::number< boost::multiprecision::et_off> Timestamp; /** - * Formats a given value with the specified SI prefix. - * @param v The value to format. - * @param unit The unit of quantity. - * @param prefix The prefix to use. + * Formats a given timestamp with the specified SI prefix. + * + * If 'prefix' is left 'unspecified', the function chooses a prefix so that + * the value in front of the decimal point is between 1 and 999. + * + * The default value "s" for the unit argument makes the most sense when + * formatting time values, but a different value can be given if the function + * is reused to format a value of another quantity. + * + * @param t The value to format. + * @param prefix The SI prefix to use. * @param precision The number of digits after the decimal separator. + * @param unit The unit of quantity. * @param sign Whether or not to add a sign also for positive numbers. * * @return The formated value. */ -QString format_si_value( - const Timestamp& v, QString unit, SIPrefix prefix = SIPrefix::unspecified, - unsigned precision = 0, bool sign = true); +QString format_time_si( + const Timestamp& t, + SIPrefix prefix = SIPrefix::unspecified, + unsigned precision = 0, + QString unit = "s", + bool sign = true); /** - * Formats a given time with the specified SI prefix. - * @param t The time value in seconds to format. - * @param prefix The prefix to use. + * Wrapper around 'format_time_si()' that interpretes the given 'precision' + * value as the number of decimal places if the timestamp would be formatted + * without a SI prefix (using 'SIPrefix::none') and adjustes the precision to + * match the given 'prefix' + * + * @param t The value to format. + * @param prefix The SI prefix to use. + * @param precision The number of digits after the decimal separator if the + * 'prefix' would be 'SIPrefix::none', see above for more information. * @param unit The unit of quantity. - * @param precision The number of digits after the decimal separator or period (.). + * @param sign Whether or not to add a sign also for positive numbers. * * @return The formated value. */ -QString format_time( - const Timestamp& t, SIPrefix prefix = SIPrefix::unspecified, - TimeUnit unit = TimeUnit::Time, unsigned precision = 0); +QString format_time_si_adjusted( + const Timestamp& t, + SIPrefix prefix, + unsigned precision = 0, + QString unit = "s", + bool sign = true); /** - * Formats a given time value with a SI prefix so that the - * value is between 1 and 999. - * @param second The time value in seconds to format. + * Formats the given timestamp using "[+-]DD:HH:MM:SS.mmm uuu nnn ppp..." format. + * + * "DD" and "HH" are left out if they would be "00" (but if "DD" is generated, + * "HH" is also always generated. The "MM:SS" part is always produced, the + * number of subsecond digits can be influenced using the 'precision' parameter. + * + * @param t The value to format. + * @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_second(const Timestamp& second); +QString format_time_minutes( + const Timestamp& t, + signed precision = 0, + bool sign = true); } // namespace util } // namespace pv diff --git a/pv/view/cursor.cpp b/pv/view/cursor.cpp index e4704be4..7432e304 100644 --- a/pv/view/cursor.cpp +++ b/pv/view/cursor.cpp @@ -20,6 +20,7 @@ #include "cursor.hpp" +#include "ruler.hpp" #include "view.hpp" #include "pv/util.hpp" @@ -55,8 +56,11 @@ bool Cursor::enabled() const QString Cursor::get_text() const { - return util::format_time(time_, view_.tick_prefix(), - view_.time_unit(), 2); + const shared_ptr other = get_other_cursor(); + const pv::util::Timestamp& diff = abs(time_ - other->time_); + + return Ruler::format_time_with_distance( + diff, time_, view_.tick_prefix(), view_.time_unit(), view_.tick_precision()); } QRectF Cursor::label_rect(const QRectF &rect) const diff --git a/pv/view/cursorpair.cpp b/pv/view/cursorpair.cpp index 7aa989da..5ee90aa1 100644 --- a/pv/view/cursorpair.cpp +++ b/pv/view/cursorpair.cpp @@ -20,6 +20,7 @@ #include "cursorpair.hpp" +#include "ruler.hpp" #include "view.hpp" #include "pv/util.hpp" @@ -162,10 +163,14 @@ void CursorPair::paint_back(QPainter &p, const ViewItemPaintParams &pp) { QString CursorPair::format_string() { const pv::util::SIPrefix prefix = view_.tick_prefix(); - 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 / fabs(delta), "Hz", pv::util::SIPrefix::unspecified, 4)); + const pv::util::Timestamp diff = abs(second_->time() - first_->time()); + + const QString s1 = Ruler::format_time_with_distance( + diff, diff, prefix, view_.time_unit(), view_.tick_precision(), false); + const QString s2 = util::format_time_si( + 1 / diff, pv::util::SIPrefix::unspecified, 4, "Hz", false); + + return QString("%1 / %2").arg(s1).arg(s2); } void CursorPair::compute_text_size(QPainter &p) diff --git a/pv/view/ruler.cpp b/pv/view/ruler.cpp index 5f7b1f67..6313ee5d 100644 --- a/pv/view/ruler.cpp +++ b/pv/view/ruler.cpp @@ -77,6 +77,38 @@ QSize Ruler::extended_size_hint() const ViewItem::HighlightRadius); } +QString Ruler::format_time_with_distance( + const pv::util::Timestamp& distance, + const pv::util::Timestamp& t, + pv::util::SIPrefix prefix, + pv::util::TimeUnit unit, + unsigned precision, + bool sign) +{ + const unsigned limit = 60; + + if (t.is_zero()) + return "0"; + + // If we have to use samples then we have no alternative formats + if (unit == pv::util::TimeUnit::Samples) + return pv::util::format_time_si_adjusted(t, prefix, precision, "sa", sign); + + // View zoomed way out -> low precision (0), big distance (>=60s) + // -> DD:HH:MM + if ((precision == 0) && (distance >= limit)) + return pv::util::format_time_minutes(t, 0, sign); + + // View in "normal" range -> medium precision, medium step size + // -> HH:MM:SS.mmm... or xxxx (si unit) if less than limit seconds + // View zoomed way in -> high precision (>3), low step size (<1s) + // -> HH:MM:SS.mmm... or xxxx (si unit) if less than limit seconds + if (abs(t) < limit) + return pv::util::format_time_si_adjusted(t, prefix, precision, "s", sign); + else + return pv::util::format_time_minutes(t, precision, sign); +} + vector< shared_ptr > Ruler::items() { const vector< shared_ptr > time_items(view_.time_items()); @@ -98,7 +130,8 @@ void Ruler::paintEvent(QPaintEvent*) if (!tick_position_cache_) { auto ffunc = [this](const pv::util::Timestamp& t) { - return util::format_time( + return format_time_with_distance( + this->view_.tick_period(), t, this->view_.tick_prefix(), this->view_.time_unit(), diff --git a/pv/view/ruler.hpp b/pv/view/ruler.hpp index f717c378..cf63eaff 100644 --- a/pv/view/ruler.hpp +++ b/pv/view/ruler.hpp @@ -72,6 +72,39 @@ public: */ QSize extended_size_hint() const; + /** + * Formats a timestamp depending on its distance to another timestamp. + * + * Heuristic function, useful when multiple timestamps should be put side by + * side. The function procedes in the following order: + * - If 't' is zero, "0" is returned. + * - If 'unit' is 'TimeUnit::Samples', 'pv::util::format_time_si_adjusted()' + * is used to format 't'. + * - If a zoomed out view is detected (determined by 'precision' and + * 'distance'), 'pv::util::format_time_minutes() is used. + * - For timestamps "near the origin" (determined by 'distance'), + * 'pv::util::format_time_si_adjusted()' is used. + * - If none of the previous was true, 'pv::util::format_time_minutes()' + * is used again. + * + * @param distance The distance between the timestamp to format and + * an adjacent one. + * @param t The value to format + * @param prefix The SI prefix to use. + * @param unit The representation of the timestamp value. + * @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. + */ + static QString format_time_with_distance( + const pv::util::Timestamp& distance, + const pv::util::Timestamp& t, + pv::util::SIPrefix prefix = pv::util::SIPrefix::unspecified, + pv::util::TimeUnit unit = pv::util::TimeUnit::Time, + unsigned precision = 0, + bool sign = true); + private: /** * Gets the time items. @@ -87,7 +120,6 @@ private: std::shared_ptr get_mouse_over_item( const QPoint &pt); -private: void paintEvent(QPaintEvent *event); void mouseDoubleClickEvent(QMouseEvent *e); diff --git a/pv/view/view.cpp b/pv/view/view.cpp index 37cc9430..9de93f34 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -60,7 +60,6 @@ using boost::shared_mutex; using pv::data::SignalData; using pv::data::Segment; -using pv::util::format_time; using pv::util::TimeUnit; using pv::util::Timestamp; @@ -594,8 +593,8 @@ void View::calculate_tick_spacing() tick_period_width = (tick_period / scale_).convert_to(); - const QString label_text = - format_time(max_time, tick_prefix, time_unit_, tick_precision); + const QString label_text = Ruler::format_time_with_distance( + tick_period, max_time, tick_prefix, time_unit_, tick_precision); label_width = m.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, label_text).width() + diff --git a/pv/widgets/timestampspinbox.cpp b/pv/widgets/timestampspinbox.cpp index 59af82f6..233ff648 100644 --- a/pv/widgets/timestampspinbox.cpp +++ b/pv/widgets/timestampspinbox.cpp @@ -113,8 +113,8 @@ void TimestampSpinBox::on_editingFinished() void TimestampSpinBox::updateEdit() { - QString newtext = pv::util::format_si_value( - value_, "s", pv::util::SIPrefix::none, precision_); + QString newtext = pv::util::format_time_si( + value_, pv::util::SIPrefix::none, precision_); lineEdit()->setText(newtext); } diff --git a/test/util.cpp b/test/util.cpp index 17c91555..21a32c5e 100644 --- a/test/util.cpp +++ b/test/util.cpp @@ -31,6 +31,7 @@ namespace { pv::util::SIPrefix unspecified = pv::util::SIPrefix::unspecified; pv::util::SIPrefix yocto = pv::util::SIPrefix::yocto; + pv::util::SIPrefix nano = pv::util::SIPrefix::nano; pv::util::SIPrefix micro = pv::util::SIPrefix::micro; pv::util::SIPrefix milli = pv::util::SIPrefix::milli; pv::util::SIPrefix none = pv::util::SIPrefix::none; @@ -63,157 +64,177 @@ BOOST_AUTO_TEST_CASE(exponent_test) BOOST_CHECK_EQUAL(exponent(SIPrefix::yotta), 24); } -BOOST_AUTO_TEST_CASE(format_si_value_test) +BOOST_AUTO_TEST_CASE(format_time_si_test) { // check prefix calculation - BOOST_CHECK_EQUAL(format_si_value(ts("0"), "V"), "0 V"); - - BOOST_CHECK_EQUAL(format_si_value(ts("1e-24"), "V"), "+1 yV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-23"), "V"), "+10 yV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-22"), "V"), "+100 yV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-21"), "V"), "+1 zV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-20"), "V"), "+10 zV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-19"), "V"), "+100 zV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-18"), "V"), "+1 aV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-17"), "V"), "+10 aV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-16"), "V"), "+100 aV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-15"), "V"), "+1 fV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-14"), "V"), "+10 fV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-13"), "V"), "+100 fV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-12"), "V"), "+1 pV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-11"), "V"), "+10 pV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-10"), "V"), "+100 pV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-9"), "V"), "+1 nV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-8"), "V"), "+10 nV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-7"), "V"), "+100 nV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-6"), "V"), QString("+1 ") + mu + "V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-5"), "V"), QString("+10 ") + mu + "V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-4"), "V"), QString("+100 ") + mu + "V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-3"), "V"), "+1 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-2"), "V"), "+10 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-1"), "V"), "+100 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e0"), "V"), "+1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e1"), "V"), "+10 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e2"), "V"), "+100 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e3"), "V"), "+1 kV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e4"), "V"), "+10 kV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e5"), "V"), "+100 kV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e6"), "V"), "+1 MV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e7"), "V"), "+10 MV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e8"), "V"), "+100 MV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e9"), "V"), "+1 GV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e10"), "V"), "+10 GV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e11"), "V"), "+100 GV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e12"), "V"), "+1 TV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e13"), "V"), "+10 TV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e14"), "V"), "+100 TV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e15"), "V"), "+1 PV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e16"), "V"), "+10 PV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e17"), "V"), "+100 PV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e18"), "V"), "+1 EV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e19"), "V"), "+10 EV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e20"), "V"), "+100 EV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e21"), "V"), "+1 ZV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e22"), "V"), "+10 ZV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e23"), "V"), "+100 ZV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e24"), "V"), "+1 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e25"), "V"), "+10 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e26"), "V"), "+100 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e27"), "V"), "+1000 YV"); - - BOOST_CHECK_EQUAL(format_si_value(ts("1234"), "V"), "+1 kV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1234"), "V", kilo, 3), "+1.234 kV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1234.5678"), "V"), "+1 kV"); - - // check if a given prefix is honored - - BOOST_CHECK_EQUAL(format_si_value(ts("1e-24"), "V", yocto), "+1 yV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-21"), "V", yocto), "+1000 yV"); - BOOST_CHECK_EQUAL(format_si_value(ts("0"), "V", yocto), "0 yV"); - - BOOST_CHECK_EQUAL(format_si_value(ts("1e-4"), "V", milli), "+0 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-4"), "V", milli, 1), "+0.1 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1000"), "V", milli), "+1000000 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("0"), "V", milli), "0 mV"); - - BOOST_CHECK_EQUAL(format_si_value(ts("1e-1"), "V", none), "+0 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-1"), "V", none, 1), "+0.1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e-1"), "V", none, 2), "+0.10 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1"), "V", none), "+1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e1"), "V", none), "+10 V"); - - BOOST_CHECK_EQUAL(format_si_value(ts("1e23"), "V", yotta), "+0 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e23"), "V", yotta, 1), "+0.1 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1e27"), "V", yotta), "+1000 YV"); - BOOST_CHECK_EQUAL(format_si_value(ts("0"), "V", yotta), "0 YV"); - - // check precision - - BOOST_CHECK_EQUAL(format_si_value(ts("1.2345678"), "V"), "+1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.4"), "V"), "+1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.5"), "V"), "+2 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.9"), "V"), "+2 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.2345678"), "V", unspecified, 2), "+1.23 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.2345678"), "V", unspecified, 3), "+1.235 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.2345678"), "V", milli, 3), "+1234.568 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.2345678"), "V", milli, 0), "+1235 mV"); - BOOST_CHECK_EQUAL(format_si_value(ts("1.2"), "V", unspecified, 3), "+1.200 V"); - - // check sign - - BOOST_CHECK_EQUAL(format_si_value(ts("-1"), "V", none, 0, true), "-1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("-1"), "V", none, 0, false), "-1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1"), "V", none, 0, true), "+1 V"); - BOOST_CHECK_EQUAL(format_si_value(ts("1"), "V", none, 0, false), "1 V"); + BOOST_CHECK_EQUAL(format_time_si(ts("0")), "0 s"); + + BOOST_CHECK_EQUAL(format_time_si(ts("1e-24")), "+1 ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-23")), "+10 ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-22")), "+100 ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-21")), "+1 zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-20")), "+10 zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-19")), "+100 zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-18")), "+1 as"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-17")), "+10 as"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-16")), "+100 as"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-15")), "+1 fs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-14")), "+10 fs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-13")), "+100 fs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-12")), "+1 ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-11")), "+10 ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-10")), "+100 ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-9")), "+1 ns"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-8")), "+10 ns"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-7")), "+100 ns"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-6")), QString("+1 ") + mu + "s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-5")), QString("+10 ") + mu + "s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-4")), QString("+100 ") + mu + "s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-3")), "+1 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-2")), "+10 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-1")), "+100 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e0")), "+1 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e1")), "+10 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e2")), "+100 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e3")), "+1 ks"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e4")), "+10 ks"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e5")), "+100 ks"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e6")), "+1 Ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e7")), "+10 Ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e8")), "+100 Ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e9")), "+1 Gs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e10")), "+10 Gs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e11")), "+100 Gs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e12")), "+1 Ts"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e13")), "+10 Ts"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e14")), "+100 Ts"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e15")), "+1 Ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e16")), "+10 Ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e17")), "+100 Ps"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e18")), "+1 Es"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e19")), "+10 Es"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e20")), "+100 Es"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e21")), "+1 Zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e22")), "+10 Zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e23")), "+100 Zs"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e24")), "+1 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e25")), "+10 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e26")), "+100 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e27")), "+1000 Ys"); + + BOOST_CHECK_EQUAL(format_time_si(ts("1234")), "+1 ks"); + BOOST_CHECK_EQUAL(format_time_si(ts("1234"), kilo, 3), "+1.234 ks"); + BOOST_CHECK_EQUAL(format_time_si(ts("1234.5678")), "+1 ks"); + + // check prefix + + BOOST_CHECK_EQUAL(format_time_si(ts("1e-24"), yocto), "+1 ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-21"), yocto), "+1000 ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("0"), yocto), "0 ys"); + + BOOST_CHECK_EQUAL(format_time_si(ts("1e-4"), milli), "+0 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-4"), milli, 1), "+0.1 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1000"), milli), "+1000000 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("0"), milli), "0 ms"); + + BOOST_CHECK_EQUAL(format_time_si(ts("1e-1"), none), "+0 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-1"), none, 1), "+0.1 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e-1"), none, 2), "+0.10 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1"), none), "+1 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e1"), none), "+10 s"); + + BOOST_CHECK_EQUAL(format_time_si(ts("1e23"), yotta), "+0 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e23"), yotta, 1), "+0.1 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("1e27"), yotta), "+1000 Ys"); + BOOST_CHECK_EQUAL(format_time_si(ts("0"), yotta), "0 Ys"); + + // check precision, rounding + + BOOST_CHECK_EQUAL(format_time_si(ts("1.2345678")), "+1 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.4")), "+1 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.5")), "+2 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.9")), "+2 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.2345678"), unspecified, 2), "+1.23 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.2345678"), unspecified, 3), "+1.235 s"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.2345678"), milli, 3), "+1234.568 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.2345678"), milli, 0), "+1235 ms"); + BOOST_CHECK_EQUAL(format_time_si(ts("1.2"), unspecified, 3), "+1.200 s"); + + // check unit and sign + + BOOST_CHECK_EQUAL(format_time_si(ts("-1"), none, 0, "V", true), "-1 V"); + BOOST_CHECK_EQUAL(format_time_si(ts("-1"), none, 0, "V", false), "-1 V"); + BOOST_CHECK_EQUAL(format_time_si(ts("1"), none, 0, "V", true), "+1 V"); + BOOST_CHECK_EQUAL(format_time_si(ts("1"), none, 0, "V", false), "1 V"); } -BOOST_AUTO_TEST_CASE(format_time_test) +BOOST_AUTO_TEST_CASE(format_time_si_adjusted_test) { - BOOST_CHECK_EQUAL(format_time(ts("-0.00005"), micro, Time, 5), QString("-50 ") + mu + "s"); - BOOST_CHECK_EQUAL(format_time(ts( "0.00005"), micro, Time, 5), QString("+50 ") + mu + "s"); - BOOST_CHECK_EQUAL(format_time(ts( "1")), "+1 s"); - BOOST_CHECK_EQUAL(format_time(ts("-1")), "-1 s"); - BOOST_CHECK_EQUAL(format_time(ts( "100")), "+1:40"); - BOOST_CHECK_EQUAL(format_time(ts("-100")), "-1:40"); - BOOST_CHECK_EQUAL(format_time(ts( "4000")), "+1:06:40"); - BOOST_CHECK_EQUAL(format_time(ts("-4000")), "-1:06:40"); - BOOST_CHECK_EQUAL(format_time(ts("12000"), kilo, Time, 0), "+3:20:00"); - BOOST_CHECK_EQUAL(format_time(ts("15000"), kilo, Time, 0), "+4:10:00"); - BOOST_CHECK_EQUAL(format_time(ts("20000"), kilo, Time, 0), "+5:33:20"); - BOOST_CHECK_EQUAL(format_time(ts("25000"), kilo, Time, 0), "+6:56:40"); - - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 0), "+123:04:05:06"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 1), "+123:04:05:06.0"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 2), "+123:04:05:06.00"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 3), "+123:04:05:06.007"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 4), "+123:04:05:06.007 0"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 5), "+123:04:05:06.007 00"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 6), "+123:04:05:06.007 008"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 7), "+123:04:05:06.007 008 0"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 8), "+123:04:05:06.007 008 00"); - BOOST_CHECK_EQUAL(format_time(ts("10641906.007008009"), none, Time, 9), "+123:04:05:06.007 008 009"); - - BOOST_CHECK_EQUAL(format_time(ts("-1.5"), milli), "-1500 ms"); - BOOST_CHECK_EQUAL(format_time(ts("-1.0"), milli), "-1000 ms"); - BOOST_CHECK_EQUAL(format_time(ts("-0.2")), "-200 ms"); - BOOST_CHECK_EQUAL(format_time(ts("-0.1")), "-100 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.0")), "0"); - BOOST_CHECK_EQUAL(format_time(ts("0.1")), "+100 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.2")), "+200 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.3")), "+300 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.4")), "+400 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.5")), "+500 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.6")), "+600 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.7")), "+700 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.8")), "+800 ms"); - BOOST_CHECK_EQUAL(format_time(ts("0.9")), "+900 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.0"), milli), "+1000 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.1"), milli), "+1100 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.2"), milli), "+1200 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.3"), milli), "+1300 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.4"), milli), "+1400 ms"); - BOOST_CHECK_EQUAL(format_time(ts("1.5"), milli), "+1500 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts("-1.5"), milli), "-1500 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts("-1.0"), milli), "-1000 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts("-0.2"), milli), "-200 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts("-0.1"), milli), "-100 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.0"), milli), "0 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.1"), milli), "+100 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.2"), milli), "+200 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.3"), milli), "+300 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.4"), milli), "+400 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.5"), milli), "+500 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.6"), milli), "+600 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.7"), milli), "+700 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.8"), milli), "+800 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "0.9"), milli), "+900 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.0"), milli), "+1000 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.1"), milli), "+1100 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.2"), milli), "+1200 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.3"), milli), "+1300 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.4"), milli), "+1400 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), milli), "+1500 ms"); + + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), milli, 6), "+1500.000 ms"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), nano, 6), "+1500000000 ns"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), nano, 8), "+1500000000 ns"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), nano, 9), "+1500000000 ns"); + BOOST_CHECK_EQUAL(format_time_si_adjusted(ts( "1.5"), nano, 10), "+1500000000.0 ns"); +} + +BOOST_AUTO_TEST_CASE(format_time_minutes_test) +{ + using namespace std::placeholders; + + auto fmt = std::bind(format_time_minutes, _1, _2, true); + + BOOST_CHECK_EQUAL(fmt(ts( 0), 0), "+0:00"); + BOOST_CHECK_EQUAL(fmt(ts( 1), 0), "+0:01"); + BOOST_CHECK_EQUAL(fmt(ts( 59), 0), "+0:59"); + BOOST_CHECK_EQUAL(fmt(ts( 60), 0), "+1:00"); + BOOST_CHECK_EQUAL(fmt(ts( -1), 0), "-0:01"); + BOOST_CHECK_EQUAL(fmt(ts( -59), 0), "-0:59"); + BOOST_CHECK_EQUAL(fmt(ts( -60), 0), "-1:00"); + BOOST_CHECK_EQUAL(fmt(ts( 100), 0), "+1:40"); + BOOST_CHECK_EQUAL(fmt(ts( -100), 0), "-1:40"); + BOOST_CHECK_EQUAL(fmt(ts( 4000), 0), "+1:06:40"); + BOOST_CHECK_EQUAL(fmt(ts(-4000), 0), "-1:06:40"); + BOOST_CHECK_EQUAL(fmt(ts(12000), 0), "+3:20:00"); + BOOST_CHECK_EQUAL(fmt(ts(15000), 0), "+4:10:00"); + BOOST_CHECK_EQUAL(fmt(ts(20000), 0), "+5:33:20"); + BOOST_CHECK_EQUAL(fmt(ts(25000), 0), "+6:56:40"); + + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 0), "+123:04:05:06"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 1), "+123:04:05:06.0"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 2), "+123:04:05:06.01"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 3), "+123:04:05:06.007"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 4), "+123:04:05:06.007 0"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 5), "+123:04:05:06.007 01"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 6), "+123:04:05:06.007 008"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 7), "+123:04:05:06.007 008 0"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 8), "+123:04:05:06.007 008 01"); + BOOST_CHECK_EQUAL(fmt(ts("10641906.007008009"), 9), "+123:04:05:06.007 008 009"); + + BOOST_CHECK_EQUAL(format_time_minutes(ts( 0), 0, false), "0:00"); + BOOST_CHECK_EQUAL(format_time_minutes(ts( 100), 0, false), "1:40"); + BOOST_CHECK_EQUAL(format_time_minutes(ts(-100), 0, false), "-1:40"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/view/ruler.cpp b/test/view/ruler.cpp index 400f845e..a6dd1c9a 100644 --- a/test/view/ruler.cpp +++ b/test/view/ruler.cpp @@ -29,7 +29,7 @@ using namespace pv::view; namespace { QString format(const pv::util::Timestamp& t) { - return pv::util::format_si_value(t, "s", pv::util::SIPrefix::none, 6); + return pv::util::format_time_si(t, pv::util::SIPrefix::none, 6); } const double e = 0.0001; -- 2.30.2