From 845a1180730d4e3c0f65b225b828ac6b2e03e7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 24 Apr 2020 14:36:10 +0200 Subject: [PATCH] [poincare] Add Unit::BuildTimeSplit and helpers for time units --- poincare/include/poincare/unit.h | 11 +++++++++++ poincare/src/unit.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 389946adb..34fad77da 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -417,7 +417,11 @@ public: // TODO: find a better way to find defines these pointers static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative might require to be fixed if the TimeRepresentatives table was changed."); static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0]; + static const Representative constexpr * MinuteRepresentative = &TimeRepresentatives[1]; static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2]; + static const Representative constexpr * DayRepresentative = &TimeRepresentatives[3]; + static const Representative constexpr * MonthRepresentative = &TimeRepresentatives[5]; + static const Representative constexpr * YearRepresentative = &TimeRepresentatives[6]; static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0]; static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; @@ -742,13 +746,20 @@ public: Unit(const UnitNode * node) : Expression(node) {} static Unit Builder(const Dimension * dimension, const Representative * representative, const Prefix * prefix); static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } + static Unit Second() { return Builder(TimeDimension, SecondRepresentative, &EmptyPrefix); } + static Unit Minute() { return Builder(TimeDimension, MinuteRepresentative, &EmptyPrefix); } static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } + static Unit Day() { return Builder(TimeDimension, DayRepresentative, &EmptyPrefix); } + static Unit Month() { return Builder(TimeDimension, MonthRepresentative, &EmptyPrefix); } + static Unit Year() { return Builder(TimeDimension, YearRepresentative, &EmptyPrefix); } static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } + static Expression BuildTimeSplit(double seconds); static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); static bool IsISEnergy(Expression & e); + static bool IsISTime(Expression & e); bool isMeter() const; bool isSecond() const; bool isKilogram() const; diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index f3b8aa28e..3bd6d524c 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -426,6 +426,34 @@ bool Unit::IsISEnergy(Expression & e) { e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusTwo(); } +bool Unit::IsISTime(Expression & e) { + return e.type() == ExpressionNode::Type::Unit && static_cast(e).isSecond(); +} + +Expression Unit::BuildTimeSplit(double seconds) { + assert(!std::isnan(seconds)); + if (std::isinf(seconds)) { + return Multiplication::Builder(Infinity::Builder(seconds < 0.0), Unit::Second()); + } + double remain = seconds; + constexpr static int numberOfTimeUnits = 6; + // This could be computed from the time representatives but we same time by using constexpr double + constexpr static double timeFactors[numberOfTimeUnits] = {365.25*24.0*60.0*60.0, 365.25/12.0*24.0*60.0*60.0, 24.0*60.0*60.0, 60.0*60.0, 60.0, 1.0 }; + Unit units[numberOfTimeUnits] = {Unit::Year(), Unit::Month(), Unit::Day(), Unit::Hour(), Unit::Minute(), Unit::Second() }; + double valuesPerUnit[numberOfTimeUnits]; + Addition a = Addition::Builder(); + for (size_t i = 0; i < numberOfTimeUnits; i++) { + valuesPerUnit[i] = std::floor(remain/timeFactors[i]); + remain -= valuesPerUnit[i]*timeFactors[i]; + if (std::fabs(remain) < Expression::Epsilon()) { + break; + } + Multiplication m = Multiplication::Builder(Float::Builder(valuesPerUnit[i]), units[i]); + a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren()); + } + return a.squashUnaryHierarchyInPlace(); +} + template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation UnitNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;