From f77258343dd315b7da9752efef227e06875d44f6 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 31 Mar 2013 00:35:25 +0100 Subject: [PATCH] CAngleUnit::sexagesimalDeg(), moved conversion to virtual method in CMeasurmenetUnit, made string conversion virtual and also moved it to CMeasurmenetUnit (=>individual formatters). Time unit added. --- samples/physicalquantities/main.cpp | 39 +++-- src/blackmisc/avverticalposition.h | 17 +- src/blackmisc/blackmisc.pro | 5 +- src/blackmisc/pqallquantities.h | 2 +- src/blackmisc/pqangle.h | 2 +- src/blackmisc/pqbase.cpp | 104 +++++++----- src/blackmisc/pqbase.h | 137 ++++++++++------ src/blackmisc/pqphysicalquantity.cpp | 86 ++++------ src/blackmisc/pqphysicalquantity.h | 88 ++++------ src/blackmisc/pqtemperature.cpp | 40 ----- src/blackmisc/pqtemperature.h | 15 +- src/blackmisc/pqtime.h | 43 +++++ src/blackmisc/pqunits.cpp | 90 +++++++++++ src/blackmisc/pqunits.h | 150 +++++++++++++++--- tests/blackmisc/blackmisctest.h | 2 +- .../blackmisc/testphysicalquantitiesbase.cpp | 17 +- tests/blackmisc/testphysicalquantitiesbase.h | 4 + 17 files changed, 542 insertions(+), 299 deletions(-) delete mode 100644 src/blackmisc/pqtemperature.cpp create mode 100644 src/blackmisc/pqtime.h create mode 100644 src/blackmisc/pqunits.cpp diff --git a/samples/physicalquantities/main.cpp b/samples/physicalquantities/main.cpp index 6dcbaf3e4..21116cf32 100644 --- a/samples/physicalquantities/main.cpp +++ b/samples/physicalquantities/main.cpp @@ -19,24 +19,25 @@ int main(int argc, char *argv[]) // cases which must not work // CMeasurementUnit mu; //must not work // CLengthUnit du1(CAngleUnit::rad()); - CLengthUnit du2(CLengthUnit::cm()); - CLengthUnit du3(CLengthUnit::ft()); - const CLength d1(5.0, CLengthUnit::ft()); // 5 ft - CLength d2(1, CLengthUnit::NM()); // 1NM - CLength d3(1, CLengthUnit::km()); - CLength d4(d3); + CLengthUnit lu1(CLengthUnit::cm()); + CLengthUnit lu2(CLengthUnit::ft()); + qDebug() << lu1 << lu2; + const CLength l1(5.0, CLengthUnit::ft()); // 5 ft + CLength l2(1, CLengthUnit::NM()); // 1NM + CLength l3(1, CLengthUnit::km()); + CLength l4(l3); qDebug() << CLengthUnit::ft(); - qDebug() << d1 << d2 << d3 << d4; - qDebug() << d1.valueRoundedWithUnit(CLengthUnit::ft(),5) - << d2.valueRoundedWithUnit(CLengthUnit::km()); - qDebug() << d3.getUnit(); + qDebug() << l1 << l2 << l3 << l4; + qDebug() << l1.valueRoundedWithUnit(CLengthUnit::ft(),5) + << l2.valueRoundedWithUnit(CLengthUnit::km()); + qDebug() << l3.getUnit(); - d2.switchUnit(CLengthUnit::ft()); // now in ft - d3 += d3; // 2km now - d3 *= 1.5;// 3km now - qDebug() << d2 << d3; + l2.switchUnit(CLengthUnit::ft()); // now in ft + l3 += l3; // 2km now + l3 *= 1.5;// 3km now + qDebug() << l2 << l3; CFrequency f1(1E6, CFrequencyUnit::Hz()); // 1MHz qDebug() << f1 << f1.valueRoundedWithUnit(CFrequencyUnit::MHz()) << f1.valueRoundedWithUnit(CFrequencyUnit::GHz(), 3); @@ -50,6 +51,8 @@ int main(int argc, char *argv[]) CAngle a1(180, CAngleUnit::deg()); CAngle a2(1.5 * CAngle::pi(), CAngleUnit::rad()); + CAngle a3(180.5, CAngleUnit::deg()); + CAngle a4(35.4336,CAngleUnit::sexagesimalDeg()); // 35.72666 a1 += a2; // a1 = d2; // must not work qDebug() << a1; @@ -60,6 +63,9 @@ int main(int argc, char *argv[]) a2.switchUnit(CAngleUnit::deg()); qDebug() << a1.unitValueRoundedWithUnit() << a1.piFactor(); qDebug() << a2; + a3.switchUnit(CAngleUnit::sexagesimalDeg()); + a4.switchUnit(CAngleUnit::deg()); + qDebug() << a3 << a4; CMass w1(1,CMassUnit::t()); CMass w2(w1); @@ -88,6 +94,11 @@ int main(int argc, char *argv[]) CLengthUnit duB(CLengthUnit::cm()); qDebug() << duB; + CTime ti1(1, CTimeUnit::h()); + CTime ti2(ti1); + ti2.switchUnit(CTimeUnit::ms()); + qDebug() << ti1 << ti2; + // bye return a.exec(); } diff --git a/src/blackmisc/avverticalposition.h b/src/blackmisc/avverticalposition.h index e8c0b4e37..475303b8e 100644 --- a/src/blackmisc/avverticalposition.h +++ b/src/blackmisc/avverticalposition.h @@ -20,7 +20,10 @@ public: */ CAviationVerticalPosition(); /*! - * \brief Default constructor + * \brief Constructor + * \param height + * \param elevation + * \param altitude */ CAviationVerticalPosition(const CLength &height, const CLength &elevation, const CLength &altitude); /*! @@ -34,6 +37,18 @@ public: * \return */ static CAviationVerticalPosition getHeight(const CLength &initValue) { return CAviationVerticalPosition(initValue, CAviationVerticalPosition::valueNotSet(), CAviationVerticalPosition::valueNotSet());} + /*! + * \brief Factory method for convenience if only one component is available + * \param initValue + * \return + */ + static CAviationVerticalPosition getElevation(const CLength &initValue) { return CAviationVerticalPosition(CAviationVerticalPosition::valueNotSet(), initValue, CAviationVerticalPosition::valueNotSet());} + /*! + * \brief Factory method for convenience if only one component is available + * \param initValue + * \return + */ + static CAviationVerticalPosition getAltitude(const CLength &initValue) { return CAviationVerticalPosition(CAviationVerticalPosition::valueNotSet(), CAviationVerticalPosition::valueNotSet(), initValue);} }; } // namespace diff --git a/src/blackmisc/blackmisc.pro b/src/blackmisc/blackmisc.pro index 24248399f..3147c4a5d 100644 --- a/src/blackmisc/blackmisc.pro +++ b/src/blackmisc/blackmisc.pro @@ -48,7 +48,8 @@ HEADERS += \ avverticalposition.h \ pqunits.h \ pqallquantities.h \ - pqlength.h + pqlength.h \ + pqtime.h SOURCES += \ logmessage.cpp \ @@ -71,7 +72,7 @@ SOURCES += \ message_system.cpp \ pqphysicalquantity.cpp \ pqbase.cpp \ - pqtemperature.cpp \ + pqunits.cpp \ avverticalposition.cpp DESTDIR = ../../lib diff --git a/src/blackmisc/pqallquantities.h b/src/blackmisc/pqallquantities.h index 1dd040955..a56d9844d 100644 --- a/src/blackmisc/pqallquantities.h +++ b/src/blackmisc/pqallquantities.h @@ -13,6 +13,6 @@ #include "blackmisc/pqspeed.h" #include "blackmisc/pqtemperature.h" #include "blackmisc/pqangle.h" - +#include "blackmisc/pqtime.h" #endif // PQUNITSALL_H diff --git a/src/blackmisc/pqangle.h b/src/blackmisc/pqangle.h index 150acaffd..8a4a02885 100644 --- a/src/blackmisc/pqangle.h +++ b/src/blackmisc/pqangle.h @@ -45,7 +45,7 @@ public: * \brief Value as factor of PI (e.g.0.5PI) * \return */ - double piFactor() const { return CPhysicalQuantity::round(this->convertedSiValueToDouble() / M_PI,6);} + double piFactor() const { return CMeasurementUnit::round(this->convertedSiValueToDouble() / M_PI,6);} }; } // namespace diff --git a/src/blackmisc/pqbase.cpp b/src/blackmisc/pqbase.cpp index 279ecaabc..decba45fc 100644 --- a/src/blackmisc/pqbase.cpp +++ b/src/blackmisc/pqbase.cpp @@ -10,7 +10,7 @@ namespace BlackMisc { * Constructor */ CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitName, double factor): - _name(name),_prefix(unitName),_factor(factor) + m_name(name),m_prefix(unitName),m_factor(factor) { // void } @@ -19,7 +19,7 @@ CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitN * Constructor */ CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier) : - _name(otherMultiplier._name), _prefix(otherMultiplier._prefix), _factor(otherMultiplier._factor) + m_name(otherMultiplier.m_name), m_prefix(otherMultiplier.m_prefix), m_factor(otherMultiplier.m_factor) { // void } @@ -30,9 +30,9 @@ CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier CMeasurementPrefix& CMeasurementPrefix::operator=(const CMeasurementPrefix &otherMultiplier) { if (this == &otherMultiplier) return *this; // Same object? Yes, so skip assignment, and just return *this - this->_name = otherMultiplier._name; - this->_prefix=otherMultiplier._prefix; - this->_factor=otherMultiplier._factor; + this->m_name = otherMultiplier.m_name; + this->m_prefix=otherMultiplier.m_prefix; + this->m_factor=otherMultiplier.m_factor; return *this; } @@ -42,7 +42,7 @@ CMeasurementPrefix& CMeasurementPrefix::operator=(const CMeasurementPrefix &othe bool CMeasurementPrefix::operator ==(const CMeasurementPrefix &otherMultiplier) const { if ( this == &otherMultiplier ) return true; - return this->_factor == otherMultiplier._factor && this->_name == otherMultiplier._name; + return this->m_factor == otherMultiplier.m_factor && this->m_name == otherMultiplier.m_name; } /** @@ -58,7 +58,7 @@ bool CMeasurementPrefix::operator !=(const CMeasurementPrefix &otherMultiplier) */ bool CMeasurementPrefix::operator >(const CMeasurementPrefix &otherMultiplier) const { - return this->_factor > otherMultiplier._factor; + return this->m_factor > otherMultiplier.m_factor; } /** @@ -66,7 +66,7 @@ bool CMeasurementPrefix::operator >(const CMeasurementPrefix &otherMultiplier) c */ bool CMeasurementPrefix::operator <(const CMeasurementPrefix &otherMultiplier) const { - return this->_factor < otherMultiplier._factor; + return this->m_factor < otherMultiplier.m_factor; } /** @@ -74,7 +74,7 @@ bool CMeasurementPrefix::operator <(const CMeasurementPrefix &otherMultiplier) c */ QDebug operator<<(QDebug d, const CMeasurementPrefix &multiplier) { - d << multiplier._name; + d << multiplier.m_name; return d; } @@ -83,7 +83,7 @@ QDebug operator<<(QDebug d, const CMeasurementPrefix &multiplier) */ CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier) { - log << multiplier._name; + log << multiplier.m_name; return log; } @@ -95,8 +95,8 @@ CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier) * Constructor */ CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &unitName, const QString &type, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI, const CMeasurementPrefix &multiplier, qint32 displayDigits, double epsilon): - _name(name), _unitName(unitName), _type(type), _isSIUnit(isSIUnit), _isSIBaseUnit(isSIBaseUnit),_displayDigits(displayDigits),_conversionFactorToSIConversionUnit(conversionFactorToSI), - _epsilon(epsilon), _multiplier(multiplier) + m_name(name), m_unitName(unitName), m_type(type), m_isSIUnit(isSIUnit), m_isSIBaseUnit(isSIBaseUnit),m_displayDigits(displayDigits),m_conversionFactorToSIConversionUnit(conversionFactorToSI), + m_epsilon(epsilon), m_multiplier(multiplier) { // void } @@ -105,9 +105,9 @@ CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &unitName, * Copy constructor */ CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &otherUnit): - _name(otherUnit._name), _unitName(otherUnit._unitName), _type(otherUnit._type), _isSIUnit(otherUnit._isSIUnit), - _isSIBaseUnit(otherUnit._isSIBaseUnit), _displayDigits(otherUnit._displayDigits),_conversionFactorToSIConversionUnit(otherUnit._conversionFactorToSIConversionUnit), - _epsilon(otherUnit._epsilon), _multiplier(otherUnit._multiplier) + m_name(otherUnit.m_name), m_unitName(otherUnit.m_unitName), m_type(otherUnit.m_type), m_isSIUnit(otherUnit.m_isSIUnit), + m_isSIBaseUnit(otherUnit.m_isSIBaseUnit), m_displayDigits(otherUnit.m_displayDigits),m_conversionFactorToSIConversionUnit(otherUnit.m_conversionFactorToSIConversionUnit), + m_epsilon(otherUnit.m_epsilon), m_multiplier(otherUnit.m_multiplier) { // void } @@ -118,15 +118,15 @@ CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &otherUnit): CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &otherUnit) { if (this == &otherUnit) return *this; // Same object? Yes, so skip assignment, and just return *this - this->_name = otherUnit._name; - this->_unitName =otherUnit._unitName; - this->_type=otherUnit._type; - this->_isSIUnit =otherUnit._isSIUnit; - this->_isSIBaseUnit =otherUnit._isSIBaseUnit; - this->_conversionFactorToSIConversionUnit=otherUnit._conversionFactorToSIConversionUnit; - this->_multiplier = otherUnit._multiplier; - this->_displayDigits=otherUnit._displayDigits; - this->_epsilon= otherUnit._epsilon; + this->m_name = otherUnit.m_name; + this->m_unitName =otherUnit.m_unitName; + this->m_type=otherUnit.m_type; + this->m_isSIUnit =otherUnit.m_isSIUnit; + this->m_isSIBaseUnit =otherUnit.m_isSIBaseUnit; + this->m_conversionFactorToSIConversionUnit=otherUnit.m_conversionFactorToSIConversionUnit; + this->m_multiplier = otherUnit.m_multiplier; + this->m_displayDigits=otherUnit.m_displayDigits; + this->m_epsilon= otherUnit.m_epsilon; return *this; } @@ -136,9 +136,9 @@ CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &otherUnit bool CMeasurementUnit::operator ==(const CMeasurementUnit &otherUnit) const { if ( this == &otherUnit ) return true; - if ( this->_type != otherUnit._type) return false; - return this->_multiplier == otherUnit._multiplier && this->_name == otherUnit._name - && this->_isSIUnit==otherUnit._isSIUnit; + if ( this->m_type != otherUnit.m_type) return false; + return this->m_multiplier == otherUnit.m_multiplier && this->m_name == otherUnit.m_name + && this->m_isSIUnit==otherUnit.m_isSIUnit; } /** @@ -146,7 +146,7 @@ bool CMeasurementUnit::operator ==(const CMeasurementUnit &otherUnit) const */ QDebug operator <<(QDebug d, const CMeasurementUnit &unit) { - d << unit._name; + d << unit.m_name; return d; } @@ -155,7 +155,7 @@ QDebug operator <<(QDebug d, const CMeasurementUnit &unit) */ CLogMessage operator<<(CLogMessage log, const CMeasurementUnit &unit) { - log << unit._name; + log << unit.m_name; return log; } @@ -170,19 +170,49 @@ bool CMeasurementUnit::operator !=(const CMeasurementUnit &otherUnit) const /** * Conversion factor from unit x to y */ -double CMeasurementUnit::conversionFactor(const CMeasurementUnit &to) const +double CMeasurementUnit::conversionToUnit(double value, const CMeasurementUnit &to) const { - return CMeasurementUnit::conversionFactor(*this, to); + if (to == (*this)) return value; + double siValue = this->convertToSiConversionUnit(value); + return to.convertFromSiConversionUnit(siValue); +} + +/*! + * Value to QString with unit, e.g. "5.00m" + * @return + */ +QString CMeasurementUnit::valueRoundedWithUnit(double value, int digits) const { + return this->toQStringRounded(value, digits).append(this->getUnitName()); +} + +/*! + * Value rounded + */ +double CMeasurementUnit::valueRounded(double value, int digits) const { + if (digits < 0) digits = this->m_displayDigits; + return CMeasurementUnit::round(value, digits); } /** - * Conversion factor from unit x to y + * Rounded to QString */ -double CMeasurementUnit::conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to) +QString CMeasurementUnit::toQStringRounded(double value, int digits) const { - if (from == to) return 1.0; - double cf = from._conversionFactorToSIConversionUnit / to._conversionFactorToSIConversionUnit; - return cf; + if (digits < 0) digits = this->m_displayDigits; + double v = CMeasurementUnit::round(value, digits); + QString s = QLocale::system().toString(v, 'f', digits); + return s; } -} // namespace BlackCore +/** + * Round utility method + */ +double CMeasurementUnit::round(double value, int digits) { + // gosh, is there no Qt method for this??? + // It's year 2013 + double m = pow(10.0,digits); + double rv = double(qRound(value * m) / m); + return rv; +} + +} // namespace diff --git a/src/blackmisc/pqbase.h b/src/blackmisc/pqbase.h index ecb5e1ef1..8ae6db707 100644 --- a/src/blackmisc/pqbase.h +++ b/src/blackmisc/pqbase.h @@ -36,9 +36,9 @@ class CMeasurementPrefix { friend CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier); private: - QString _name; //!< name, e.g. "kilo" - QString _prefix; //!< prefix, e.g. "k" for kilo - double _factor; //!< factor, e.g. 1000 for kilo 1/100 for centi + QString m_name; //!< name, e.g. "kilo" + QString m_prefix; //!< prefix, e.g. "k" for kilo + double m_factor; //!< factor, e.g. 1000 for kilo 1/100 for centi /*! * Constructor by parameters * \brief CMeasurementMultiplier @@ -86,26 +86,26 @@ public: /*! * \brief Cast as double */ - operator double() const { return this->_factor; } + operator double() const { return this->m_factor; } /*! * \brief Cast as QString */ - operator QString() const { return this->_name;} + operator QString() const { return this->m_name;} /*! * \brief Factor, e.g.1000 for "kilo" * \return */ - double getFactor() const { return this->_factor;} + double getFactor() const { return this->m_factor;} /*! * \brief Name, e.g. "kilo" * \return */ - QString getName() const { return this->_name; } + QString getName() const { return this->m_name; } /*! * \brief Prefix, e.g. "k" for "kilo" * \return */ - QString getPrefix() const { return this->_prefix; } + QString getPrefix() const { return this->m_prefix; } // --- static units, always use these for initialization // --- Remark: Static initialization in C++ is random, this is why no static members @@ -115,37 +115,43 @@ public: * \brief Unit "None" * \return */ - static CMeasurementPrefix& None() { static CMeasurementPrefix none("", "", 0.0); return none;} + static const CMeasurementPrefix& None() { static CMeasurementPrefix none("", "", 0.0); return none;} /*! * \brief Unit "One" * \return */ - static CMeasurementPrefix& One() { static CMeasurementPrefix one("one", "", 1.0); return one;} + static const CMeasurementPrefix& One() { static CMeasurementPrefix one("one", "", 1.0); return one;} /*! * \brief Unit "mega" * \return */ - static CMeasurementPrefix& M() { static CMeasurementPrefix mega("mega", "M", 1E6); return mega;} + static const CMeasurementPrefix& M() { static CMeasurementPrefix mega("mega", "M", 1E6); return mega;} /*! * \brief Unit "kilo" * \return */ - static CMeasurementPrefix& k() { static CMeasurementPrefix kilo("kilo", "k", 1000.0); return kilo;} + static const CMeasurementPrefix& k() { static CMeasurementPrefix kilo("kilo", "k", 1000.0); return kilo;} /*! * \brief Unit "giga" * \return */ - static CMeasurementPrefix& G() { static CMeasurementPrefix giga("giga", "G", 1E9); return giga;} + static const CMeasurementPrefix& G() { static CMeasurementPrefix giga("giga", "G", 1E9); return giga;} /*! * \brief Unit "hecto" * \return */ - static CMeasurementPrefix& h() { static CMeasurementPrefix hecto("hecto", "h", 100.0); return hecto;} + static const CMeasurementPrefix& h() { static CMeasurementPrefix hecto("hecto", "h", 100.0); return hecto;} /*! * \brief Unit "centi" * \return */ - static CMeasurementPrefix& c() { static CMeasurementPrefix centi("centi", "c", 0.01); return centi;} + static const CMeasurementPrefix& c() { static CMeasurementPrefix centi("centi", "c", 0.01); return centi;} + /*! + * \brief Unit "milli" + * \return + */ + static const CMeasurementPrefix& m() { static CMeasurementPrefix milli("milli", "m", 1E-03); return milli;} + }; // --------------------------------------------------------------------------------- @@ -174,20 +180,19 @@ class CMeasurementUnit { friend CLogMessage operator<<(CLogMessage log, const CMeasurementUnit &unit); private: - QString _name; //!< name, e.g. "meter" - QString _unitName; //!< unit name, e.g. "m" - QString _type; //!< type,such as distance. Somehow redundant, but simplifies unit comparisons - bool _isSIUnit; //!< is this a SI unit? - bool _isSIBaseUnit; //!< SI base unit? - double _conversionFactorToSIConversionUnit; //!< factor to convert to SI, set to 0 if not applicable (rare cases, e.g. temperature) - double _epsilon; //!< values with differences below epsilon are the equal - qint32 _displayDigits; //!< standard rounding dor string conversions - CMeasurementPrefix _multiplier; //!< multiplier + QString m_name; //!< name, e.g. "meter" + QString m_unitName; //!< unit name, e.g. "m" + QString m_type; //!< type,such as distance. Somehow redundant, but simplifies unit comparisons + bool m_isSIUnit; //!< is this a SI unit? + bool m_isSIBaseUnit; //!< SI base unit? + double m_conversionFactorToSIConversionUnit; //!< factor to convert to SI, set to 0 if not applicable (rare cases, e.g. temperature) + double m_epsilon; //!< values with differences below epsilon are the equal + qint32 m_displayDigits; //!< standard rounding dor string conversions + CMeasurementPrefix m_multiplier; //!< multiplier (kilo, Mega) protected: /*! * Constructor by parameter - *\brief CMeasurementUnit * \param name * \param unitName * \param isSIUnit @@ -209,6 +214,12 @@ protected: * \return */ CMeasurementUnit &operator =(const CMeasurementUnit &otherUnit); +protected: + /*! + * \brief Conversion factor to SI conversion unit + * \return + */ + double getConversionFactorToSI() const { return this->m_conversionFactorToSIConversionUnit; } public: /*! @@ -227,65 +238,101 @@ public: * \brief Representing an SI unit? Examples: kilometer, meter, hertz * \return */ - bool isSiUnit() const { return this->_isSIUnit;} + bool isSiUnit() const { return this->m_isSIUnit;} /*! * \brief Representing an base SI unit? Examples: second, meter * \return */ - bool isSiBaseUnit() const { return this->_isSIUnit;} + bool isSiBaseUnit() const { return this->m_isSIUnit;} /*! * \brief Representing an SI base unit? Example: meter * \return */ - bool isUnprefixedSiUnit() const { return this->_isSIUnit && this->_multiplier.getFactor() == 1; } + bool isUnprefixedSiUnit() const { return this->m_isSIUnit && this->m_multiplier.getFactor() == 1; } /*! * \brief Name such as "meter" * \return */ - QString getName() const { return this->_name; } + QString getName() const { return this->m_name; } /*! * \brief Unit name such as "m" * \return */ - QString getUnitName() const { return this->_unitName; } - /*! - * \brief Factor toconvert to SI unit (e.g.meter,hertz) - * \return - */ - QString getType() const { return this->_type; } + QString getUnitName() const { return this->m_unitName; } /*! * \brief Type such as "distance", "frequency" * \return */ - double getConversionFactorToSIConversionUnit() const { return this->_conversionFactorToSIConversionUnit;} + QString getType() const { return this->m_type; } + /*! + * Given value to conversion SI conversion unit (e.g. meter, hertz). + * Standard implementaion is simply factor based. + * \param value + * \return + */ + virtual double convertToSiConversionUnit(double value) const { return value * this->m_conversionFactorToSIConversionUnit; } + /*! + * \brief Value from SI conversion unit to this unit. + * Standard implementaion is simply factor based. + * \param value + * \return + */ + virtual double convertFromSiConversionUnit(double value) const { return value / this->m_conversionFactorToSIConversionUnit; } + /*! + * Rounded string utility method, virtual so units can have + * specialized formatting + * \param value + * \param digits + * \return + */ + virtual QString toQStringRounded(double value, int digits =-1) const; + /*! + * \brief Rounded value + * \param value + * \param digits + * \return + */ + double valueRounded(double value, int digits = -1) const; + /*! + * \brief Value rounded with unit, e.g. "5.00m", "30kHz" + * \param value + * \param digits + * \return + */ + virtual QString valueRoundedWithUnit(double value, int digits = -1) const; /*! * \brief Threshold for rounding * \return */ - double getEpsilon() const { return this->_epsilon;} + double getEpsilon() const { return this->m_epsilon;} /*! * \brief getDisplayDigits * \return */ - qint32 getDisplayDigits() const { return this->_displayDigits; } + qint32 getDisplayDigits() const { return this->m_displayDigits; } /*! * \brief Multiplier such as "kilo" * \return */ - CMeasurementPrefix getMultiplier() const { return this->_multiplier; } + CMeasurementPrefix getMultiplier() const { return this->m_multiplier; } /*! * \brief Factor to convert to given unit * \param to * \return */ - double conversionFactor(const CMeasurementUnit &to) const; + double conversionToUnit(double value, const CMeasurementUnit &to) const; + + // -------------------------------------------------------------------- + // -- static + // -------------------------------------------------------------------- + /*! - * \brief Factor to convert between given units - * \param from - * \param to + * \brief Utility round method + * \param value + * \param digits * \return */ - static double conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to); + static double round(double value, int digits); /*! * \brief Unit is not specified * \return @@ -293,6 +340,6 @@ public: static CMeasurementUnit& None() { static CMeasurementUnit none("none", "", "", false, false, 0.0, CMeasurementPrefix::None(), 0, 0); return none;} }; -} // namespace BlackMisc +} // namespace #endif // PQBASE_H diff --git a/src/blackmisc/pqphysicalquantity.cpp b/src/blackmisc/pqphysicalquantity.cpp index 0682c7c18..579a3a15c 100644 --- a/src/blackmisc/pqphysicalquantity.cpp +++ b/src/blackmisc/pqphysicalquantity.cpp @@ -5,8 +5,8 @@ namespace BlackMisc { /** * Constructor by integer */ -template CPhysicalQuantity::CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit, const CPhysicalQuantityUnitConverter unitConverter) : - m_unit(unit), m_conversionSiUnit(siConversionUnit), m_unitConverter(unitConverter) +template CPhysicalQuantity::CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit) : + m_unit(unit), m_conversionSiUnit(siConversionUnit) { this->setUnitValue(baseValue); } @@ -14,8 +14,8 @@ template CPhysicalQuantity::CPhysicalQuantity(qint32 /** * Constructor by double */ -template CPhysicalQuantity::CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit, const CPhysicalQuantityUnitConverter unitConverter) : - m_unit(unit), m_conversionSiUnit(siConversionUnit),m_unitConverter(unitConverter) +template CPhysicalQuantity::CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit) : + m_unit(unit), m_conversionSiUnit(siConversionUnit) { this->setUnitValue(baseValue); } @@ -25,7 +25,7 @@ template CPhysicalQuantity::CPhysicalQuantity(double */ template CPhysicalQuantity::CPhysicalQuantity(const CPhysicalQuantity &otherQuantity) : m_unitValueD(otherQuantity.m_unitValueD), m_unitValueI(otherQuantity.m_unitValueI), m_convertedSiUnitValueD(otherQuantity.m_convertedSiUnitValueD), - m_isIntegerBaseValue(otherQuantity.m_isIntegerBaseValue), m_unit(otherQuantity.m_unit), m_conversionSiUnit(otherQuantity.m_conversionSiUnit), m_unitConverter(otherQuantity.m_unitConverter) + m_isIntegerBaseValue(otherQuantity.m_isIntegerBaseValue), m_unit(otherQuantity.m_unit), m_conversionSiUnit(otherQuantity.m_conversionSiUnit) { // void } @@ -46,7 +46,7 @@ template bool CPhysicalQuantity::operator ==(const C if(this == &otherQuantity) return true; if(this->m_unit.getType()!= otherQuantity.m_unit.getType()) return false; - // some special case for best quality + // some special cases for best quality double diff; const double lenient = 1.001; // even diff already has a rounding issue to be avoided if (this->m_unit == otherQuantity.m_unit) { @@ -87,7 +87,6 @@ template CPhysicalQuantity& CPhysicalQuantity this->m_isIntegerBaseValue = otherQuantity.m_isIntegerBaseValue; this->m_unit = otherQuantity.m_unit; this->m_conversionSiUnit = otherQuantity.m_conversionSiUnit; - this->m_unitConverter = otherQuantity.m_unitConverter; return *this; } @@ -249,7 +248,7 @@ template bool CPhysicalQuantity::switchUnit(const MU { if (this->m_unit == newUnit) return true; if (this->m_unit.getType() != newUnit.getType()) return false; // not possible - double cf = this->m_unitConverter(this, newUnit); + double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit); this->m_unit = newUnit; this->setUnitValue(cf); return true; @@ -281,17 +280,7 @@ template void CPhysicalQuantity::setUnitValue(double * Set SI value */ template void CPhysicalQuantity::setConversionSiUnitValue() { - this->m_convertedSiUnitValueD = this->m_unitConverter(this, this->m_conversionSiUnit); -} - -/** - * Standard conversion by factor, used in most cases, in some cases (e.g. CTemperature) arbitrary converter - */ -template double CPhysicalQuantity::standardUnitFactorValueConverter(const CPhysicalQuantity *quantity, const MU &otherUnit) { - if (quantity->m_unit == MU::None() || quantity->m_unitValueD == 0.0) return 0.0; - if (quantity->m_unit == otherUnit) return quantity->m_unitValueD; - double f = quantity->m_unit.conversionFactor(otherUnit); - return f * quantity->m_unitValueD; + this->m_convertedSiUnitValueD = this->m_unit.convertToSiConversionUnit(this->m_unitValueD); } /** @@ -299,18 +288,7 @@ template double CPhysicalQuantity::standardUnitFacto */ template double CPhysicalQuantity::unitValueToDoubleRounded(int digits) const { - if (digits < 1) digits = this->m_unit.getDisplayDigits(); - return CPhysicalQuantity::round(this->m_unitValueD, digits); -} - -/** - * Rounded to QString - */ -template QString CPhysicalQuantity::toQStringRounded(double value, int digits) -{ - double v =CPhysicalQuantity::round(value, digits); - QString s = QLocale::system().toString(v, 'f', digits); - return s; + return this->m_unit.valueRounded(this->m_unitValueD, digits); } /** @@ -318,8 +296,15 @@ template QString CPhysicalQuantity::toQStringRounded */ template QString CPhysicalQuantity::unitValueToQStringRounded(int digits) const { - if (digits < 1) digits = this->m_unit.getDisplayDigits(); - return CPhysicalQuantity::toQStringRounded(this->m_unitValueD, digits); + return this->m_unit.toQStringRounded(this->m_unitValueD, digits); +} + +/** + * Rounded with unit + */ +template QString CPhysicalQuantity::unitValueRoundedWithUnit(int digits) const +{ + return this->m_unit.valueRoundedWithUnit(this->m_unitValueD, digits); } /** @@ -328,15 +313,7 @@ template QString CPhysicalQuantity::unitValueToQStri template QString CPhysicalQuantity::convertedSiValueToQStringRounded(int digits) const { if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits(); - return CPhysicalQuantity::toQStringRounded(this->m_convertedSiUnitValueD, digits); -} - -/** - * Value rounded in original unit - */ -template QString CPhysicalQuantity::unitValueRoundedWithUnit(int digits) const { - if (digits < 1) digits = this->m_unit.getDisplayDigits(); - return this->unitValueToQStringRounded(digits).append(this->m_unit.getUnitName()); + return this->m_conversionSiUnit.toQStringRounded(this->m_convertedSiUnitValueD, digits); } /** @@ -354,8 +331,7 @@ template QString CPhysicalQuantity::valueRoundedWith { if (unit == this->m_unit) return this->unitValueRoundedWithUnit(digits); if (unit == this->m_conversionSiUnit) return this->convertedSiValueRoundedWithUnit(digits); - if (digits < 0) digits = unit.getDisplayDigits(); - return CPhysicalQuantity::toQStringRounded(this->value(unit), digits).append(unit.getUnitName()); + return unit.valueRoundedWithUnit(this->value(unit),digits); } /** @@ -363,8 +339,7 @@ template QString CPhysicalQuantity::valueRoundedWith */ template double CPhysicalQuantity::valueRounded(const MU &unit, int digits) const { - if (digits < 1) digits = unit.getDisplayDigits(); - return CPhysicalQuantity::round(this->value(unit),digits); + return unit.valueRounded(this->value(unit),digits); } /** @@ -372,8 +347,9 @@ template double CPhysicalQuantity::valueRounded(cons */ template double CPhysicalQuantity::value(const MU &unit) const { + if (unit == this->m_unit) return this->m_unitValueD; if (unit == this->m_conversionSiUnit) return this->m_convertedSiUnitValueD; - double v = this->m_unitConverter(this, unit); + double v = unit.convertFromSiConversionUnit(this->m_convertedSiUnitValueD); return v; } @@ -383,21 +359,11 @@ template double CPhysicalQuantity::value(const MU &u template double CPhysicalQuantity::convertedSiValueToDoubleRounded(int digits) const { if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits(); - return CPhysicalQuantity::round(this->m_convertedSiUnitValueD, digits); + return this->m_conversionSiUnit.valueRounded(this->m_convertedSiUnitValueD, digits); } -/** - * Round utility method - */ -template double CPhysicalQuantity::round(double value, int digits) { - // gosh, is there no Qt method for this??? - // It's year 2013 - double m = pow(10.0,digits); - double rv = double(qRound(value * m) / m); - return rv; -} -// see here for the reason of this forward initialization +// see here for the reason of this forward instants // http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html template class CPhysicalQuantity; template class CPhysicalQuantity; @@ -406,5 +372,7 @@ template class CPhysicalQuantity; template class CPhysicalQuantity; template class CPhysicalQuantity; template class CPhysicalQuantity; +template class CPhysicalQuantity; + } // namespace diff --git a/src/blackmisc/pqphysicalquantity.h b/src/blackmisc/pqphysicalquantity.h index bb2786a9d..a5eb5c268 100644 --- a/src/blackmisc/pqphysicalquantity.h +++ b/src/blackmisc/pqphysicalquantity.h @@ -23,7 +23,7 @@ template class CPhysicalQuantity * Our converter function, should be implemented as static method of the quantity * classes for clarity */ - typedef double (*CPhysicalQuantityUnitConverter)(const CPhysicalQuantity *quantity, const MU &unit); + typedef double (*CPhysicalQuantityUnitConverter)(const PQ *quantity, const MU &unit); /*! * Stream operator for debugging @@ -31,9 +31,9 @@ template class CPhysicalQuantity * \param debug * \param quantity * \return - * \remarks has to be in the header files toavoid templatelink errors + * \remarks Has to be in the header files to avoid template link errors */ - friend QDebug operator<<(QDebug debug, const CPhysicalQuantity &quantity) { + friend QDebug operator<<(QDebug debug, const CPhysicalQuantity &quantity) { QString v = quantity.unitValueRoundedWithUnit(-1); debug << v; return debug; @@ -45,9 +45,9 @@ template class CPhysicalQuantity * \param log * \param quantity * \return - * \remarks has to be in the header files toavoid templatelink errors + * \remarks Has to be in the header files toavoid templatelink errors */ - friend CLogMessage operator<<(CLogMessage log, const CPhysicalQuantity &quantity) { + friend CLogMessage operator<<(CLogMessage log, const CPhysicalQuantity &quantity) { QString v = quantity.unitValueRoundedWithUnit(-1); log << v; return log; @@ -58,16 +58,6 @@ private: double m_unitValueD; //!< value backed by double double m_convertedSiUnitValueD; //!< SI unit value bool m_isIntegerBaseValue; //!< flag integer? / double? - CPhysicalQuantityUnitConverter m_unitConverter; //! *quantity, const MU &otherUnit); protected: MU m_unit; //!< unit @@ -80,16 +70,14 @@ protected: * \param siBaseUnit * \param unitConverter */ - CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit, - const CPhysicalQuantityUnitConverter unitConverter = CPhysicalQuantity::standardUnitFactorValueConverter); + CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit); /*! * \brief Constructor with double * \param baseValue * \param unit * \param siBaseUnit */ - CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit, - const CPhysicalQuantityUnitConverter unitConverter = CPhysicalQuantity::standardUnitFactorValueConverter); + CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit); /*! * \brief Init by integer * \param baseValue @@ -110,11 +98,11 @@ public: * \brief Copy constructor * \param otherQuantity */ - CPhysicalQuantity(const CPhysicalQuantity &otherQuantity); + CPhysicalQuantity(const CPhysicalQuantity &otherQuantity); /*! * \brief Virtual destructor */ - virtual ~CPhysicalQuantity(); + virtual ~CPhysicalQuantity(); /*! * \brief Unit of the distance * \return @@ -146,12 +134,6 @@ public: * \return */ bool isUnprefixedSiUnit() const { return this->m_unit.isUnprefixedSiUnit(); } - /*! - * \brief Value to QString with unit, e.g. "5.00m" - * \param digits - * @return - */ - QString unitValueRoundedWithUnit(int digits = -1) const; /*! * \brief Value in given unit * \param unit @@ -182,11 +164,17 @@ public: * @return */ double unitValueToDouble() const { return this->m_unitValueD;} + /*! + * \brief Value to QString with unit, e.g. "5.00m" + * \param digits + * @return + */ + QString unitValueRoundedWithUnit(int digits = -1) const; /*! * \brief SI value to integer * @return */ - qint32 siBaseUnitValueToInteger() const { return CPhysicalQuantity::round(this->m_convertedSiUnitValueD,0);} + qint32 siBaseUnitValueToInteger() const { return CMeasurementUnit::round(this->m_convertedSiUnitValueD,0);} /*! * \brief SI value to double * @return @@ -213,7 +201,7 @@ public: * \brief SI value as integer * \return */ - qint32 convertedSiValueToInteger() const { return (qint32)CPhysicalQuantity::round(this->m_convertedSiUnitValueD,0);} + qint32 convertedSiValueToInteger() const { return static_cast(CMeasurementUnit::round(this->m_convertedSiUnitValueD,0));} /*! * \brief Rounded SI value by n digits * \param digits @@ -258,13 +246,13 @@ public: * \param multiply * \return */ - CPhysicalQuantity &operator *=(double multiply); + CPhysicalQuantity &operator *=(double multiply); /*! * \brief Divide operator /= * \param divide * @return */ - CPhysicalQuantity &operator /=(double divide); + CPhysicalQuantity &operator /=(double divide); /*! * \brief Operator * * \param multiply @@ -282,55 +270,55 @@ public: * \param otherQuantity * @return */ - bool operator==(const CPhysicalQuantity &otherQuantity) const; + bool operator==(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Not equal operator != * \param otherQuantity * @return */ - bool operator!=(const CPhysicalQuantity &otherQuantity) const; + bool operator!=(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Plus operator += * \param otherQuantity * @return */ - CPhysicalQuantity &operator +=(const CPhysicalQuantity &otherQuantity); + CPhysicalQuantity &operator +=(const CPhysicalQuantity &otherQuantity); /*! * \brief Minus operator-= * \param otherQuantity * @return */ - CPhysicalQuantity &operator -=(const CPhysicalQuantity &otherQuantity); + CPhysicalQuantity &operator -=(const CPhysicalQuantity &otherQuantity); /*! * \brief Greater operator > * \param otherQuantity * @return */ - bool operator >(const CPhysicalQuantity &otherQuantity) const; + bool operator >(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Less operator < * \param otherQuantity * @return */ - bool operator <(const CPhysicalQuantity &otherQuantity) const; + bool operator <(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Less equal operator <= * \param otherQuantity * @return */ - bool operator <=(const CPhysicalQuantity &otherQuantity) const; + bool operator <=(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Greater equal operator >= * \param otherQuantity * @return */ - bool operator >=(const CPhysicalQuantity &otherQuantity) const; + bool operator >=(const CPhysicalQuantity &otherQuantity) const; /*! * \brief Assignment operator = * \param otherQuantity * @return */ - CPhysicalQuantity &operator =(const CPhysicalQuantity &otherQuantity); + CPhysicalQuantity &operator =(const CPhysicalQuantity &otherQuantity); /*! * \brief Plus operator + * \param otherQuantity @@ -344,26 +332,6 @@ public: */ PQ operator -(const PQ &otherQuantity) const; - - // -------------------------------------------------------------------- - // -- static - // -------------------------------------------------------------------- - - /*! - * \brief Utility round method - * \param value - * \param digits - * \return - */ - static double round(double value, int digits); - - /*! - * \brief Rounded string utility method - * \param value - * \param digits - * \return - */ - static QString toQStringRounded(double value, int digits); }; } // namespace BlackCore diff --git a/src/blackmisc/pqtemperature.cpp b/src/blackmisc/pqtemperature.cpp deleted file mode 100644 index 9cb52d57d..000000000 --- a/src/blackmisc/pqtemperature.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "blackmisc/pqtemperature.h" - -namespace BlackMisc { - -/** - * Specialized method for temperture - */ -double CTemperature::temperaturUnitConverter(const CPhysicalQuantity *quantity, const CTemperatureUnit &otherUnit) -{ - CTemperature *me = (CTemperature*) quantity; // allow me access to protected - if (me->m_unit == otherUnit) return me->siBaseUnitValueToDouble(); - - double siValue; - // I always convert via SI Unit, other I would need too many conversions - if(otherUnit == me->m_conversionSiUnit) { - // here I expect a conversion to SI is required and not done yet - if(me->m_unit == CTemperatureUnit::C()) { - siValue = quantity->unitValueToDouble() + 273.15; - } else if(me->m_unit == CTemperatureUnit::F()) { - siValue = (me->unitValueToDouble() + 459.67) *5.0 / 9.0; - } else{ - // TODO: EXCEPTION - } - } else { - // here I expect the SI value is already set - siValue = quantity->siBaseUnitValueToDouble(); - } - - // from SI - if (otherUnit == me->m_conversionSiUnit) return siValue; - if(otherUnit == CTemperatureUnit::C()) { - return siValue - 273.15; - } else if(me->m_unit == CTemperatureUnit::F()) { - return (siValue * 9.0 / 5.0) - 459.67; - } - // TODO: Exception - return 0; -} - -} // namespace diff --git a/src/blackmisc/pqtemperature.h b/src/blackmisc/pqtemperature.h index 027032f0d..c27df8603 100644 --- a/src/blackmisc/pqtemperature.h +++ b/src/blackmisc/pqtemperature.h @@ -10,20 +10,11 @@ namespace BlackMisc { */ class CTemperature : public CPhysicalQuantity { -private: - /*! - * \brief Convert into another temperature unit - * \param quantity - * \param otherUnit - * \return - */ - static double temperaturUnitConverter(const CPhysicalQuantity *quantity, const CTemperatureUnit &otherUnit); - public: /*! * \brief Default constructor */ - CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::K(), CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {} + CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::K(), CTemperatureUnit::K()) {} /** *\brief Copy constructor */ @@ -33,13 +24,13 @@ public: * \param value * \param unit */ - CTemperature(qint32 value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {} + CTemperature(qint32 value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K()) {} /*! *\brief Init by double value * \param value * \param unit */ - CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {} + CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K()) {} /*! * \brief Destructor */ diff --git a/src/blackmisc/pqtime.h b/src/blackmisc/pqtime.h new file mode 100644 index 000000000..66f3724e4 --- /dev/null +++ b/src/blackmisc/pqtime.h @@ -0,0 +1,43 @@ +#ifndef PQTIME_H +#define PQTIME_H + +#include "pqphysicalquantity.h" + +namespace BlackMisc { + +/*! + * Time class, e.g. "ms", "hour", "s", "day" + * \author KWB + */ +class CTime : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CTime() : CPhysicalQuantity(0, CTimeUnit::s(), CTimeUnit::s()) {} + /** + *\brief Copy constructor + */ + CTime(const CPhysicalQuantity &time): CPhysicalQuantity(time) {} + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CTime(qint32 value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit, CTimeUnit::s()) {} + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CTime(double value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit, CTimeUnit::s()) {} + /*! + * \brief Destructor + */ + virtual ~CTime() {} +}; +} // namespace + + +#endif // PQTIME_H diff --git a/src/blackmisc/pqunits.cpp b/src/blackmisc/pqunits.cpp new file mode 100644 index 000000000..715256ac3 --- /dev/null +++ b/src/blackmisc/pqunits.cpp @@ -0,0 +1,90 @@ +#include "blackmisc/pqunits.h" + +namespace BlackMisc { + +/** + * Convert to SI + */ +double CTemperatureUnit::convertToSiConversionUnit(double value) const +{ + double v = value + this->m_conversionOffsetToSi; + v *= this->getConversionFactorToSI(); + return v; +} + +/** + * Convert from SI + */ +double CTemperatureUnit::convertFromSiConversionUnit(double value) const +{ + double v = value / this->getConversionFactorToSI(); + v -= this->m_conversionOffsetToSi; + return v; +} + +/** + * Convert from SI + */ +double CAngleUnit::convertFromSiConversionUnit(double value) const +{ + double v; + // still a design flaw since I have to distinguish as per type + // but an own converter per object was really too much + if ((*this) == CAngleUnit::sexagesimalDeg()) { + value = value * 180 / M_PI; // degree + v = floor(value); + double c = value - v; + double mr = c * 60.0; + double m = floor(mr); // minutes + double s = (mr-m) * 60; // seconds + rest fraction + v = (v + (m/100) + (s/10000)); + } else { + v = CMeasurementUnit::convertFromSiConversionUnit(value); + } + return v; +} + +/** + * Convert to SI + */ +double CAngleUnit::convertToSiConversionUnit(double value) const +{ + // still a design flaw since I have to distinguish as per type + // but an own converter per object was really too much + double v; + if ((*this) == CAngleUnit::sexagesimalDeg()) { + double v = floor(value); // degrees + double c = value - v; + c = c * 100.0; + double m = floor(c); + c = c - m; + m /= 60.0; // minutes back to decimals + double s = c / 36.0; // seconds back to decimals + v = v + m + s; + return v / 180.0 * M_PI; + } else { + v = CMeasurementUnit::convertToSiConversionUnit(value); + } + return v; +} + +/** + * Rounded to QString + */ +QString CAngleUnit::toQStringRounded(double value, int digits) const +{ + QString s; + if ((*this) == CAngleUnit::sexagesimalDeg()) { + double de = floor(value); + double mi = floor((value-de)*100.0); + double se = floor((value-de-mi/100.0)*1000000) / 100.0; + QString ses = QLocale::system().toString(se, 'f', 2); + s = QString::number(de).append(this->getUnitName()).append(QString::number(mi)) + .append("'").append(ses).append("\""); + } else { + s = CMeasurementUnit::toQStringRounded(value, digits); + } + return s; +} + +} diff --git a/src/blackmisc/pqunits.h b/src/blackmisc/pqunits.h index 7ecd82302..f4be9ffdb 100644 --- a/src/blackmisc/pqunits.h +++ b/src/blackmisc/pqunits.h @@ -1,18 +1,22 @@ #ifndef PQUNITS_H #define PQUNITS_H #include "blackmisc/pqbase.h" +#include +// +// Used with the template for quantities. This is the reason for +// having all units in one file, since template requires concrete instantiations +// namespace BlackMisc { /*! * Specialized class for distance units (meter, foot, nautical miles). - * \author KWB + * \author KWB, MS */ class CLengthUnit : public CMeasurementUnit { private: /*! - * Constructor - * \brief Distance unit + * \brief Constructor Distance unit * \param name * \param unitName * \param isSIUnit @@ -66,8 +70,7 @@ public: class CAngleUnit : public CMeasurementUnit { private: /*! - * Constructor - * \brief Angle units: Radian, degree + * \brief Constructor angle units: Radian, degree * \param name * \param unitName * \param isSIUnit @@ -82,20 +85,45 @@ private: // void } public: - CAngleUnit(const CAngleUnit &otherUnit) : CMeasurementUnit(otherUnit) - { - // void - } /*! - * \brief Meter m + * \brief Copy constructor + * \param otherUnit + */ + CAngleUnit(const CAngleUnit &otherUnit) : CMeasurementUnit(otherUnit) { } + /*! + * \brief Convert to SI conversion unit, specific for angle + * \param value + * \return + */ + virtual double CAngleUnit::convertToSiConversionUnit(double value) const; + /*! + * \brief Convert from SI conversion unit, specific for angle + * \param value + * \return + */ + virtual double CAngleUnit::convertFromSiConversionUnit(double value) const; + /*! + * \brief Special conversion to QString for sexagesimal degrees. + * \param value + * \param digits + * \return + */ + virtual QString toQStringRounded(double value, int digits) const; + /*! + * \brief Radians * \return */ static const CAngleUnit& rad() { static CAngleUnit rad("radian", "rad", true); return rad;} /*! - * \brief Nautical miles NM + * \brief Degrees * \return */ static const CAngleUnit& deg() { static CAngleUnit deg("degree", "°", false, M_PI/180); return deg;} + /*! + * \brief Sexagesimal degree (degree, minute, seconds) + * \return + */ + static const CAngleUnit& sexagesimalDeg() { static CAngleUnit deg("segadecimal degree", "°", false, M_PI/180); return deg;} }; /*! @@ -151,8 +179,7 @@ public: class CMassUnit : public CMeasurementUnit { private: /*! - * Constructor - * \brief Mass units + * \brief Constructor mass units * \param name * \param unitName * \param isSIUnit @@ -183,7 +210,7 @@ public: * \brief Tonne, aka metric tonne (1000kg) * \return */ - static const CMassUnit& t() { static CMassUnit t("tonne", "t", true, false, 1000.0, CMeasurementPrefix::One(), 3); return t;} + static const CMassUnit& t() { static CMassUnit t("tonne", "t", false, false, 1000.0, CMeasurementPrefix::One(), 3); return t;} /*! * \brief Pound, aka mass pound * \return @@ -257,30 +284,51 @@ public: * \author KWB */ class CTemperatureUnit : public CMeasurementUnit { +private: + double m_conversionOffsetToSi; private: /*! - * Constructor - * \brief Temperature unit + * Constructor temperature unit * \param name * \param unitName * \param isSIUnit * \param isSIBaseUnit * \param conversionFactorToSI + * \param temperatureOffsetToSI * \param mulitplier * \param displayDigits * \param epsilon */ - CTemperatureUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : - CMeasurementUnit(name, unitName, "temperature", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + CTemperatureUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, double temperatureOffsetToSI=0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : + CMeasurementUnit(name, unitName, "temperature", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon), m_conversionOffsetToSi(temperatureOffsetToSI) {} public: /*! * \brief Copy constructor * \param otherUnit */ - CTemperatureUnit(const CTemperatureUnit &otherUnit) : CMeasurementUnit(otherUnit) + CTemperatureUnit(const CTemperatureUnit &otherUnit) : CMeasurementUnit(otherUnit), m_conversionOffsetToSi(otherUnit.m_conversionOffsetToSi) {} + /*! + * Assigment operator + */ + CTemperatureUnit &CTemperatureUnit::operator =(const CTemperatureUnit &otherUnit) { - // void + if (this == &otherUnit) return *this; // Same object? Yes, so skip assignment, and just return *this + CMeasurementUnit::operator = (otherUnit); + this->m_conversionOffsetToSi = otherUnit.m_conversionOffsetToSi; + return (*this); } + /*! + * \brief Convert to SI conversion unit, specific for temperature + * \param value + * \return + */ + virtual double CTemperatureUnit::convertToSiConversionUnit(double value) const; + /*! + * \brief Convert from SI conversion unit, specific for temperature + * \param value + * \return + */ + virtual double CTemperatureUnit::convertFromSiConversionUnit(double value) const; /*! * \brief Kelvin * \return @@ -290,12 +338,13 @@ public: * \brief Centigrade C * \return */ - static const CTemperatureUnit& C() { static CTemperatureUnit C("centigrade", "°C", false, false);return C;} + static const CTemperatureUnit& C() { static CTemperatureUnit C("centigrade", "°C", false, false, 1.0, 273.15);return C;} /*! * \brief Fahrenheit F * \return */ - static const CTemperatureUnit& F() { static CTemperatureUnit F("Fahrenheit", "°F", false, false, 5.0/9.0);return F;} + static const CTemperatureUnit& F() { static CTemperatureUnit F("Fahrenheit", "°F", false, false, 5.0/9.0, 459.67);return F;} + }; /*! @@ -306,7 +355,7 @@ class CSpeedUnit : public CMeasurementUnit { private: /*! * Constructor - * \brief CSpeedUnit + * \brief Speed unit constructor * \param name * \param unitName * \param isSIUnit @@ -320,7 +369,7 @@ private: CMeasurementUnit(name, unitName, "speed", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} public: /*! - * Downcast copy constructor, allows to implement methods in base class + * Constructor, allows to implement methods in base class * \param otherUnit */ CSpeedUnit(const CSpeedUnit &otherUnit) : CMeasurementUnit(otherUnit) {} @@ -351,6 +400,59 @@ public: static const CSpeedUnit& km_h() { static CSpeedUnit kmh("kilometer/hour", "km/h", false, false, 1.0/3.6, CMeasurementPrefix::One(), 1);return kmh;} }; +/*! + * Specialized class for time units (ms, hour, min). + * \author KWB + */ +class CTimeUnit : public CMeasurementUnit { +private: + /*! + * Constructor + * \brief Time unit constructor + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CTimeUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : + CMeasurementUnit(name, unitName, "time", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} +public: + /*! + * Constructor, allows to implement methods in base class + * \param otherUnit + */ + CTimeUnit(const CTimeUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Second s + * \return + */ + static const CTimeUnit& s() { static CTimeUnit s("second", "s", true, true, 1, CMeasurementPrefix::None(), 1); return s;} + /*! + * \brief Millisecond ms + * \return + */ + static const CTimeUnit& ms() { static CTimeUnit ms("millisecond", "ms", true, false, 1E-03, CMeasurementPrefix::m(), 0); return ms;} + /*! + * \brief Hour + * \return + */ + static const CTimeUnit& h() { static CTimeUnit h("hour", "h", false, false, 3600, CMeasurementPrefix::None(), 1); return h;} + /*! + * \brief Minute + * \return + */ + static const CTimeUnit& min() { static CTimeUnit min("minute", "min", false, false, 60, CMeasurementPrefix::None(), 2); return min;} + /*! + * \brief Day + * \return + */ + static const CTimeUnit& d() { static CTimeUnit day("day", "d", false, false, 3600*24, CMeasurementPrefix::None(), 1); return day;} + +}; } // namespace #endif // PQUNITS_H diff --git a/tests/blackmisc/blackmisctest.h b/tests/blackmisc/blackmisctest.h index 580552dc6..76b8f2572 100644 --- a/tests/blackmisc/blackmisctest.h +++ b/tests/blackmisc/blackmisctest.h @@ -4,7 +4,7 @@ /** * @namespace BlackMiscTest * Unit test for BlackMisc. Unit test do have their own namespace, so - * the regular namespace BlackMiscis completely free of unit tests. + * the regular namespace BlackMisc is completely free of unit tests. * Add any new tests to TestMain::unitMain as shown there in the pattern. */ diff --git a/tests/blackmisc/testphysicalquantitiesbase.cpp b/tests/blackmisc/testphysicalquantitiesbase.cpp index a4de6e593..9e7274a43 100644 --- a/tests/blackmisc/testphysicalquantitiesbase.cpp +++ b/tests/blackmisc/testphysicalquantitiesbase.cpp @@ -93,9 +93,11 @@ void TestPhysicalQuantitiesBase::angleTests() { CAngle a1(180, CAngleUnit::deg()); CAngle a2(1.5 * CAngle::pi(), CAngleUnit::rad()); + CAngle a3(35.4336,CAngleUnit::sexagesimalDeg()); // 35.72666 a2.switchUnit(CAngleUnit::deg()); QVERIFY2(a2.unitValueToInteger() == 270, qPrintable(QString("1.5Pi should be 270deg, not %1 deg").arg(a2.unitValueToInteger()))); - QVERIFY2(a1.piFactor() == 1, qPrintable(QString("Pi should be 1PI,not %1").arg(a1.piFactor()))); + QVERIFY2(a1.piFactor() == 1, qPrintable(QString("Pi should be 1PI, not %1").arg(a1.piFactor()))); + QVERIFY2(a3.valueRounded(CAngleUnit::deg()) == 35.73, "Expecting 35.73"); } /** @@ -137,13 +139,24 @@ void TestPhysicalQuantitiesBase::temperatureTests() CTemperature t1(0, CTemperatureUnit::C()); // 0C CTemperature t2(1, CTemperatureUnit::F()); // 1F CTemperature t3(220.15, CTemperatureUnit::F()); + CTemperature t4(10, CTemperatureUnit::F()); QVERIFY2(t1.convertedSiValueToDoubleRounded() == 273.15, qPrintable(QString("0C shall be 273.15K, not %1 K").arg(t1.convertedSiValueToDoubleRounded()))); QVERIFY2(t2.valueRounded(CTemperatureUnit::C()) == -17.22, qPrintable(QString("1F shall be -17.22C, not %1 C").arg(t2.valueRounded(CTemperatureUnit::C())))); QVERIFY2(t3.valueRounded(CTemperatureUnit::C()) == 104.53, qPrintable(QString("220.15F shall be 104.53C, not %1 C").arg(t3.valueRounded(CTemperatureUnit::C())))); + QVERIFY2(t4.valueRounded(CTemperatureUnit::K()) == 260.93, qPrintable(QString("10F shall be 260.93K, not %1 K").arg(t4.valueRounded(CTemperatureUnit::K())))); } /** - * @brief Just testing obvious memory create / destruct flaws + * Temperature tests + */ +void TestPhysicalQuantitiesBase::timeTests() +{ + CTime t1(1, CTimeUnit::h()); + QVERIFY2(t1.siBaseUnitValueToInteger() == 3600, "1hour shall be 3600s"); +} + +/** + * Just testing obvious memory create / destruct flaws */ void TestPhysicalQuantitiesBase::memoryTests() { diff --git a/tests/blackmisc/testphysicalquantitiesbase.h b/tests/blackmisc/testphysicalquantitiesbase.h index f90950436..bccd02482 100644 --- a/tests/blackmisc/testphysicalquantitiesbase.h +++ b/tests/blackmisc/testphysicalquantitiesbase.h @@ -52,6 +52,10 @@ private slots: * \brief Testing temperature */ void temperatureTests(); + /*! + * \brief Testing time + */ + void timeTests(); /*! * \brief Testing construction / destruction in memory */