From 4d7b9aa2a9ab3727f4af5bd5ec841ba7a507dafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 23 Apr 2020 09:59:27 +0200 Subject: [PATCH] [poincare] Add watthour representation to classic unit conversion --- poincare/include/poincare/integer.h | 1 + poincare/include/poincare/rational.h | 4 ++++ poincare/include/poincare/unit.h | 10 ++++++++++ poincare/src/multiplication.cpp | 9 +++++++++ poincare/src/unit.cpp | 17 +++++++++++++++++ poincare/test/simplification.cpp | 1 + 6 files changed, 42 insertions(+) diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 66e948bf5..7140ccd80 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -121,6 +121,7 @@ public: bool isThree() const { return (numberOfDigits() == 1 && digit(0) == 3 && !m_negative); }; bool isTen() const { return (numberOfDigits() == 1 && digit(0) == 10 && !m_negative); }; bool isMinusOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && m_negative); }; + bool isMinusTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && m_negative); }; bool isZero() const { return (numberOfDigits() == 0); }; bool isEven() const { return ((digit(0) & 1) == 0); } diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 091e6fbc9..c1af28415 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -45,8 +45,10 @@ public: // Basic test bool isZero() const { return unsignedNumerator().isZero(); } bool isOne() const { return signedNumerator().isOne() && isInteger(); } + bool isTwo() const { return signedNumerator().isTwo() && isInteger(); } bool isThree() const { return signedNumerator().isThree() && isInteger(); } bool isMinusOne() const { return signedNumerator().isMinusOne() && isInteger(); } + bool isMinusTwo() const { return signedNumerator().isMinusTwo() && isInteger(); } bool isHalf() const { return signedNumerator().isOne() && denominator().isTwo(); } bool isMinusHalf() const { return signedNumerator().isMinusOne() && denominator().isTwo(); } bool isTen() const { return signedNumerator().isTen() && isInteger(); } @@ -90,8 +92,10 @@ public: bool isNegative() const { return node()->isNegative(); } bool isZero() const { return node()->isZero(); } bool isOne() const { return node()->isOne(); } + bool isTwo() const { return node()->isTwo(); } bool isThree() const { return node()->isThree(); } bool isMinusOne() const { return node()->isMinusOne(); } + bool isMinusTwo() const { return node()->isMinusTwo(); } bool isHalf() const { return node()->isHalf(); } bool isMinusHalf() const { return node()->isMinusHalf(); } bool isTen() const { return node()->isTen(); } diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index 0be5807e8..40421e479 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -415,10 +415,13 @@ public: NegativePrefixes), }; // 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 * HourRepresentative = &TimeRepresentatives[2]; static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0]; + static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0]; static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0]; + static const Representative constexpr * WattRepresentative = &PowerRepresentatives[0]; static constexpr const Dimension DimensionTable[] = { /* The current table is sorted from most to least simple units. * The order determines the behavior of simplification. @@ -724,8 +727,11 @@ public: ), }; // TODO: find a better way to find defines these pointers + static_assert(sizeof(DimensionTable)/sizeof(Dimension) == 23, "The Unit::TimeDimension, Unit::DistanceDimension and so on might require to be fixed if the Dimension table was changed."); static const Dimension constexpr * TimeDimension = &DimensionTable[0] ; static const Dimension constexpr * DistanceDimension = &DimensionTable[1]; + static const Dimension constexpr * MassDimension = &DimensionTable[2]; + static const Dimension constexpr * PowerDimension = &DimensionTable[11]; static const Dimension constexpr * VolumeDimension = &DimensionTable[sizeof(DimensionTable)/sizeof(Dimension)-1]; static constexpr const Unit::Dimension * DimensionTableUpperBound = @@ -738,11 +744,14 @@ public: static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); } static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); } static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); } + static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); } static bool IsISSpeed(Expression & e); static bool IsISVolume(Expression & e); + static bool IsISEnergy(Expression & e); bool isMeter() const; bool isSecond() const; + bool isKilogram() const; // Simplification Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); @@ -750,6 +759,7 @@ public: static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0; static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0; + static constexpr double JouleToWatthourFactor = 1.0/3600.0; private: UnitNode * node() const { return static_cast(Expression::node()); } Expression removeUnit(Expression * unit); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 6eb3af9c1..59c40e618 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -480,6 +480,15 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu units = Unit::Liter(); static_cast(units).chooseBestMultipleForValue(value, 1, reductionContext); } + if (Unit::IsISEnergy(units)) { + value *= Unit::JouleToWatthourFactor; + Unit w = Unit::Watt(); + units = Multiplication::Builder( + w, + Unit::Hour() + ); + w.chooseBestMultipleForValue(value, 1, reductionContext); + } // TODO: what to do if no classic conversion? } if (result.isUninitialized()) { diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index 89e1734fd..f19004a1a 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -361,6 +361,11 @@ bool Unit::isMeter() const { return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix; } + +bool Unit::isKilogram() const { + return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix; +} + bool Unit::IsISSpeed(Expression & e) { // Form m*s^-1 return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 2 && @@ -377,6 +382,18 @@ bool Unit::IsISVolume(Expression & e) { e.childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).convert().isThree(); } +bool Unit::IsISEnergy(Expression & e) { + // Form _kg*_m^2*_s^-2 + return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 3 && + e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert().isKilogram() && + e.childAtIndex(1).type() == ExpressionNode::Type::Power && + e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isMeter(); + e.childAtIndex(1).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isTwo() && + e.childAtIndex(2).type() == ExpressionNode::Type::Power && + e.childAtIndex(2).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert().isSecond(); + e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert().isMinusTwo(); +} + 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; diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index b636e13b8..0badb52f2 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -1287,6 +1287,7 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); assert_parsed_expression_simplify_to("0.2_m^3", "200×_L", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); assert_parsed_expression_simplify_to("0.000012_m^3", "1.2×_cL", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); + assert_parsed_expression_simplify_to("3600_J", "1×_W×_h", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion); } QUIZ_CASE(poincare_simplification_user_function) {