diff --git a/client.pro b/client.pro index fb6ec2edd..d9e35bd3b 100644 --- a/client.pro +++ b/client.pro @@ -1,26 +1,17 @@ TEMPLATE = subdirs - CONFIG += ordered WITH_BLACKMISC = ON - WITH_BLACKCORE = ON - WITH_BLACKD = ON - WITH_BLACKBOX = ON - WITH_SAMPLES = ON #WITH_DRIVER_FSX = ON - #WITH_DRIVER_FS9 = ON - #WITH_DRIVER_XPLANE = ON - #WITH_UNITTESTS = ON - equals(WITH_BLACKMISC, ON) { SUBDIRS += src/blackmisc } @@ -56,11 +47,9 @@ equals(WITH_SAMPLES, ON) { SUBDIRS += samples/geodetic2ecef/sample_geodetic2ecef.pro SUBDIRS += samples/interpolator/sample_interpolator.pro SUBDIRS += samples/logging/sample_logging.pro + SUBDIRS += samples/physicalquantities/sample_physicalquantities.pro } equals(WITH_UNITTESTS, ON) { - SUBDIRS += + SUBDIRS += tests/blackcore/test_blackcore.pro } - - - diff --git a/samples/Logging/sample_logging.pro b/samples/Logging/sample_logging.pro index 795f495c4..dd541ed42 100644 --- a/samples/Logging/sample_logging.pro +++ b/samples/Logging/sample_logging.pro @@ -8,7 +8,6 @@ CONFIG += console CONFIG -= app_bundle DEPENDPATH += . ../../src - INCLUDEPATH += . ../../src SOURCES += main.cpp\ diff --git a/samples/physicalquantities/main.cpp b/samples/physicalquantities/main.cpp new file mode 100644 index 000000000..cf66a56ea --- /dev/null +++ b/samples/physicalquantities/main.cpp @@ -0,0 +1,55 @@ +#include +#include +#include "blackcore/pqdistance.h" +#include "blackcore/pqfrequency.h" +#include "blackcore/pqspeed.h" +#include "blackcore/pqangle.h" +#include "blackcore/pqmass.h" +#include "blackcore/pqpressure.h" + +using namespace BlackCore; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + const CDistance d1(5.0, CDistanceUnit::ft()); // 5 ft + CDistance d2(1, CDistanceUnit::NM()); // 1NM + CDistance d3(1, CDistanceUnit::km()); + qDebug() << d1 << d2 << d3; + qDebug() << d1.valueRoundedWithUnit(CDistanceUnit::ft(),5) + << d2.valueRoundedWithUnit(CDistanceUnit::km()); + qDebug() << d3.getUnit(); + + d2.switchUnit(CDistanceUnit::ft()); // now in ft + d3 += d3; // 2km now + d3 *= 1.5;// 3km now + qDebug() << d2 << d3; + + CFrequency f1(1E6); // 1MHz + qDebug() << f1 << f1.valueRoundedWithUnit(CFrequencyUnit::MHz()) << f1.valueRoundedWithUnit(CFrequencyUnit::GHz(), 3); + + CSpeed s1 = CSpeed(100, CSpeedUnit::km_h()); + CSpeed s2 = CSpeed(1000,CSpeedUnit::ft_min()); + CSpeed s3 = CSpeed(s2); + s3.switchUnit(CSpeedUnit::m_s()); + qDebug() << s1 << s1.convertedSiValueRoundedWithUnit() << s1.valueRoundedWithUnit(CSpeedUnit::NM_h()); + qDebug() << s2 << s3; + + CAngle a1(180, CAngleUnit::deg()); + CAngle a2(1.5 * CAngle::pi()); + a2.switchUnit(CAngleUnit::deg()); + qDebug() << a1.unitValueRoundedWithUnit() << a1.piFactor(); + qDebug() << a2; + + CMass w1(1,CMassUnit::t()); + CMass w2(w1); + w2.switchUnit(CMassUnit::lb()); + qDebug() << w1 << w1.valueRoundedWithUnit(CMassUnit::kg()) << w2; + + CPressure p1(1013.25, CPressureUnit::hPa()); + qDebug() << p1 << p1.valueRoundedWithUnit(CPressureUnit::psi()) << p1.valueRoundedWithUnit(CPressureUnit::inHg()); + + // bye + return a.exec(); +} diff --git a/samples/physicalquantities/sample_physicalquantities.pro b/samples/physicalquantities/sample_physicalquantities.pro new file mode 100644 index 000000000..7cd7c00a8 --- /dev/null +++ b/samples/physicalquantities/sample_physicalquantities.pro @@ -0,0 +1,24 @@ +QT += core +QT -= gui + +TARGET = sample_physicalquantities +TEMPLATE = app + +CONFIG += console +CONFIG -= app_bundle + +DEPENDPATH += . ../../src/blackcore +INCLUDEPATH += . ../../src +SOURCES += main.cpp + +win32-msvc* { + PRE_TARGETDEPS += ../../lib/blackcore.lib + LIBS += ../../lib/blackcore.lib +} + +!win32-msvc* { + PRE_TARGETDEPS += ../../lib/libblackcore.a + LIBS += ../../lib/libblackcore.a +} + +DESTDIR = ../../bin diff --git a/src/blackcore/blackcore.pro b/src/blackcore/blackcore.pro index 22f89c23a..bc25673bb 100644 --- a/src/blackcore/blackcore.pro +++ b/src/blackcore/blackcore.pro @@ -29,6 +29,15 @@ HEADERS += \ multiplayer.h \ ned.h \ plane.h \ + pqdistance.h \ + pqphysicalquantity.h \ + pqfrequency.h \ + pqbase.h \ + pqspeed.h \ + pqangle.h \ + pqmass.h \ + pqpressure.h \ + pqtemperature.h \ simulator.h \ vector_3d.h \ vector_geo.h @@ -43,9 +52,18 @@ SOURCES += \ multiplayer.cpp \ ned.cpp \ plane.cpp \ + pqdistance.cpp \ + pqphysicalquantity.cpp \ + pqfrequency.cpp \ + pqbase.cpp \ + pqspeed.cpp \ + pqangle.cpp \ + pqmass.cpp \ + pqpressure.cpp \ + pqtemperature.cpp \ simulator.cpp \ vector_3d.cpp \ - vector_geo.cpp + vector_geo.cpp \ DESTDIR = ../../lib diff --git a/src/blackcore/pqangle.cpp b/src/blackcore/pqangle.cpp new file mode 100644 index 000000000..00a632c20 --- /dev/null +++ b/src/blackcore/pqangle.cpp @@ -0,0 +1,37 @@ +#include "pqangle.h" + +namespace BlackCore { + +/** + * Default constructor + */ +CAngle::CAngle() : CPhysicalQuantity(0, CAngleUnit::rad(), CAngleUnit::rad()) +{ + // void +} + +/** + * Constructor + */ +CAngle::CAngle(const CPhysicalQuantity &angle): CPhysicalQuantity(angle) +{ + //void +} + +/** + * Constructor + */ +CAngle::CAngle(qint32 value, const CAngleUnit &unit) : CPhysicalQuantity(value, unit, CAngleUnit::rad()) +{ + // void +} + +/** + * Constructor + */ +CAngle::CAngle(double value, const CAngleUnit &unit) : CPhysicalQuantity(value, unit, CAngleUnit::rad()) +{ + // void +} + +} // namespace diff --git a/src/blackcore/pqangle.h b/src/blackcore/pqangle.h new file mode 100644 index 000000000..21b9e896c --- /dev/null +++ b/src/blackcore/pqangle.h @@ -0,0 +1,95 @@ +#ifndef PQANGLE_H +#define PQANGLE_H +#include "pqphysicalquantity.h" +#include "math.h" + +namespace BlackCore { + +/*! + * Specialized class for angles (degrees, radian). + * \author KWB + */ +class CAngleUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief Angle units: Radian, degree + * \param name + * \param unitName + * \param isSIUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CAngleUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : + CMeasurementUnit(name, unitName, "angle", isSIUnit, false, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CAngleUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Meter m + * \return + */ + static CAngleUnit& rad() { static CAngleUnit rad("radian", "rad", true); return rad;} + /*! + * \brief Nautical miles NM + * \return + */ + static CAngleUnit& deg() { static CAngleUnit deg("degree", "°", false, M_PI/180); return deg;} +}; + +/*! + * \brief Physical unit degree + * \author KWB + */ +class CAngle : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CAngle(); + /** + *\brief downcast copy constructor + */ + CAngle(const CPhysicalQuantity &angle); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CAngle(qint32 value, const CAngleUnit &unit = CAngleUnit::rad()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CAngle(double value, const CAngleUnit &unit = CAngleUnit::rad()); + /*! + * \brief Unit of the distance + * \return + */ + CAngleUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CAngleUnit getConversionSiUnit() const { return this->_conversionSiUnit; } + /*! + * \brief Convenience method PI + * \return + */ + const static double pi() { return M_PI;} + /*! + * \brief Value as factor of PI (e.g.0.5PI) + * \return + */ + double piFactor() const { return CPhysicalQuantity::round(this->convertedSiValueToDouble() / M_PI,6);} + +}; +} // namespace blackCore + +#endif // PQANGLE_H diff --git a/src/blackcore/pqbase.cpp b/src/blackcore/pqbase.cpp new file mode 100644 index 000000000..d451e0881 --- /dev/null +++ b/src/blackcore/pqbase.cpp @@ -0,0 +1,170 @@ +#include "pqbase.h" + +namespace BlackCore { + +// ----------------------------------------------------------------------- +// --- Mulitplier -------------------------------------------------------- +// ----------------------------------------------------------------------- + +/** + * Constructor + */ +CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitName, double factor): + _name(name),_prefix(unitName),_factor(factor) +{ + // void +} + +/** + * Constructor + */ +CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier) : + _name(otherMultiplier._name), _prefix(otherMultiplier._prefix), _factor(otherMultiplier._factor) +{ + // void +} + +/** + * Assignment operator + */ +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; + return *this; +} + +/** + * Equal? + */ +bool CMeasurementPrefix::operator ==(const CMeasurementPrefix &otherMultiplier) const +{ + if ( this == &otherMultiplier ) return true; + return this->_factor == otherMultiplier._factor && this->_name == otherMultiplier._name; +} + +/** + * Not equal + */ +bool CMeasurementPrefix::operator !=(const CMeasurementPrefix &otherMultiplier) const +{ + return !(*this == otherMultiplier); +} + +/** + * Greater? + */ +bool CMeasurementPrefix::operator >(const CMeasurementPrefix &otherMultiplier) const +{ + return this->_factor > otherMultiplier._factor; +} + +/** + * Less? + */ +bool CMeasurementPrefix::operator <(const CMeasurementPrefix &otherMultiplier) const +{ + return this->_factor < otherMultiplier._factor; +} + +/** + * Stream to debug + */ +QDebug operator<<(QDebug d, const CMeasurementPrefix &multiplier) +{ + d << multiplier._name; + return d; +} + +// ----------------------------------------------------------------------- +// --- Measurement unit -------------------------------------------------- +// ----------------------------------------------------------------------- + +/** + * 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) +{ + // void +} + +/* + * 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) +{ + // void +} + +/** + * Assigment operator + */ +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; + return *this; +} + +/** + * Equal operator + */ +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; +} + +/** + * Unequal operator + */ +bool CMeasurementUnit::operator !=(const CMeasurementUnit &otherUnit) const +{ + return !(otherUnit == *this); +} + +/** + * Stream to debug + */ +QDebug operator <<(QDebug d, const CMeasurementUnit &unit) +{ + d << unit._name; + return d; +} + +/** + * Conversion factor from unit x to y + */ +double CMeasurementUnit::conversionFactor(const CMeasurementUnit &to) const +{ + return CMeasurementUnit::conversionFactor(*this, to); +} + +/** + * Conversion factor from unit x to y + */ +double CMeasurementUnit::conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to) +{ + if (from == to) return 1.0; + double cf = from._conversionFactorToSIConversionUnit / to._conversionFactorToSIConversionUnit; + return cf; +} + +} // namespace BlackCore diff --git a/src/blackcore/pqbase.h b/src/blackcore/pqbase.h new file mode 100644 index 000000000..b139d4059 --- /dev/null +++ b/src/blackcore/pqbase.h @@ -0,0 +1,280 @@ +//! This Source Code Form is subject to the terms of the Mozilla Public +//! License, v. 2.0. If a copy of the MPL was not distributed with this +//! file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#ifndef PQBASE_H +#define PQBASE_H + +#include +#include +#include + +namespace BlackCore { + +/*! + * Typical prefixes (multipliers) such as kilo, mega, hecto. + * See here for an overview. + * Use the static values such CMeasurementMultiplier::k() as to specify values. + * \author KWB + */ +class CMeasurementPrefix { + /*! + * \brief Stream << overload to be used in debugging messages + * \param d + * \param multiplier + * \return + */ + friend QDebug operator<<(QDebug d, 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 + /*! + * Constructor by parameters + * \brief CMeasurementMultiplier + * \param name + * \param prefixName + * \param factor + */ + CMeasurementPrefix(const QString &name, const QString &prefixName, double factor); +public: + /*! + * \brief Copy constructor + * \param otherMultiplier + */ + CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier); + /*! + * \brief Assigmnet operator = + * \param otherMultiplier + * \return + */ + CMeasurementPrefix &operator =(const CMeasurementPrefix &otherMultiplier); + /*! + * \brief Equal operator == + * \param otherMultiplier + * \return + */ + bool operator == (const CMeasurementPrefix &otherMultiplier) const; + /*! + * \brief Unequal operator != + * \param otherMultiplier + * \return + */ + bool operator != (const CMeasurementPrefix &otherMultiplier) const; + /*! + * \brief Greater operator > + * \param otherMultiplier + * \return + */ + bool operator > (const CMeasurementPrefix &otherMultiplier) const; + /*! + * \brief Less operator < + * \param otherMultiplier + * \return + */ + bool operator < (const CMeasurementPrefix &otherMultiplier) const; + /*! + * \brief Cast as double + */ + operator double() const { return this->_factor; } + /*! + * \brief Cast as QString + */ + operator QString() const { return this->_name;} + /*! + * \brief Factor, e.g.1000 for "kilo" + * \return + */ + double getFactor() const { return this->_factor;} + /*! + * \brief Name, e.g. "kilo" + * \return + */ + QString getName() const { return this->_name; } + /*! + * \brief Prefix, e.g. "k" for "kilo" + * \return + */ + QString getPrefix() const { return this->_prefix; } + + // --- static units, always use these for initialization + // --- Remark: Static initialization in C++ is random, this is why no static members + // --- are used + + /*! + * \brief Unit "None" + * \return + */ + static CMeasurementPrefix& None() { static CMeasurementPrefix none("", "", 0.0); return none;} + /*! + * \brief Unit "One" + * \return + */ + static 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;} + /*! + * \brief Unit "kilo" + * \return + */ + static 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;} + /*! + * \brief Unit "hecto" + * \return + */ + static 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;} +}; + +// --------------------------------------------------------------------------------- +// --- Unit +// --------------------------------------------------------------------------------- + +/** + * Base class for all units, such as meter, hertz. + */ +class CMeasurementUnit { + /*! + * \brief Stream << overload to be used in debugging messages + * \param d + * \param unit + * \return + */ + friend QDebug operator<<(QDebug d, 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 + double _epsilon; //!< values with differences below epsilon are the equal + qint32 _displayDigits; //!< standard rounding dor string conversions + CMeasurementPrefix _multiplier; //!< multiplier + +protected: + /*! + * Constructor by parameter + *\brief CMeasurementUnit + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \param multiplier + * \param displayDigits + * \param epsilon + */ + CMeasurementUnit(const QString &name, const QString &unitName, const QString &type, bool isSiUnit, bool isSiBaseUnit, double conversionFactorToSI = 1, const CMeasurementPrefix &multiplier = CMeasurementPrefix::None(), qint32 displayDigits = 2, double epsilon = 1E-10); + +public: + /*! + * \brief Copy constructor + * \param otherUnit + */ + CMeasurementUnit(const CMeasurementUnit &otherUnit); + /*! + * \brief Assignment operator = + * \param otherUnit + * \return + */ + CMeasurementUnit &operator =(const CMeasurementUnit &otherUnit); + /*! + * \brief Equal operator == + * \param otherUnit + * \return + */ + bool operator == (const CMeasurementUnit &otherUnit) const; + /*! + * \brief Unequal operator != + * \param otherUnit + * \return + */ + bool operator != (const CMeasurementUnit &otherUnit) const; + /*! + * \brief Representing an SI unit? Examples: kilometer, meter, hertz + * \return + */ + bool isSiUnit() const { return this->_isSIUnit;} + /*! + * \brief Representing an base SI unit? Examples: second, meter + * \return + */ + bool isSiBaseUnit() const { return this->_isSIUnit;} + /*! + * \brief Representing an SI base unit? Example: meter + * \return + */ + bool isUnprefixedSiUnit() const { return this->_isSIUnit && this->_multiplier.getFactor() == 1; } + /*! + * \brief Name such as "meter" + * \return + */ + QString getName() const { return this->_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; } + /*! + * \brief Type such as "distance", "frequency" + * \return + */ + double getConversionFactorToSIConversionUnit() const { return this->_conversionFactorToSIConversionUnit;} + /*! + * \brief Threshold for rounding + * \return + */ + double getEpsilon() const { return this->_epsilon;} + /*! + * \brief getDisplayDigits + * \return + */ + qint32 getDisplayDigits() const { return this->_displayDigits; } + /*! + * \brief Multiplier such as "kilo" + * \return + */ + CMeasurementPrefix getMultiplier() const { return this->_multiplier; } + /*! + * \brief Factor to convert to given unit + * \param to + * \return + */ + virtual double conversionFactor(const CMeasurementUnit &to) const; + /*! + * \brief Factor to convert between given units + * \param from + * \param to + * \return + */ + static double conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to); + /*! + * \brief Unit is not specified + * \return + */ + static CMeasurementUnit& None() { static CMeasurementUnit none("none", "", "", false, false, 0.0, CMeasurementPrefix::None(), 0, 0); return none;} +}; + +} // namespace BlackCore + +#endif // PQBASE_H diff --git a/src/blackcore/pqdistance.cpp b/src/blackcore/pqdistance.cpp new file mode 100644 index 000000000..e8e9c612c --- /dev/null +++ b/src/blackcore/pqdistance.cpp @@ -0,0 +1,37 @@ +#include "pqdistance.h" + +namespace BlackCore { + +/** + * Default Constructor + */ +CDistance::CDistance(): CPhysicalQuantity(0, CDistanceUnit::m(),CDistanceUnit::m()) +{ + //void +} + +/** + * Constructor + */ +CDistance::CDistance(const CPhysicalQuantity &distance): CPhysicalQuantity(distance) +{ + //void +} + +/** + * Constructor + */ +CDistance::CDistance(qint32 value, const CDistanceUnit &unit) : CPhysicalQuantity(value, unit, CDistanceUnit::m()) +{ + // void +} + +/** + * Constructor + */ +CDistance::CDistance(double value, const CDistanceUnit &unit) : CPhysicalQuantity(value, unit, CDistanceUnit::m()) +{ + // void +} + +} // namespace BlackCore diff --git a/src/blackcore/pqdistance.h b/src/blackcore/pqdistance.h new file mode 100644 index 000000000..0ade6bdca --- /dev/null +++ b/src/blackcore/pqdistance.h @@ -0,0 +1,98 @@ +#ifndef PQDISTANCE_H +#define PQDISTANCE_H +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for distance units (meter, foot, nautical miles). + * \author KWB + */ +class CDistanceUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief Distance unit + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CDistanceUnit(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, "distance", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CDistanceUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Meter m + * \return + */ + static CDistanceUnit& m() { static CDistanceUnit m("meter", "m", true, true); return m;} + /*! + * \brief Nautical miles NM + * \return + */ + static CDistanceUnit& NM() { static CDistanceUnit NM("nautical miles", "NM", false, false, 1000.0*1.85200, CMeasurementPrefix::One(), 3);return NM;} + /*! + * \brief Foot ft + * \return + */ + static CDistanceUnit& ft() { static CDistanceUnit ft("foot", "ft", false, false, 0.3048, CMeasurementPrefix::One(), 0); return ft;} + /*! + * \brief Kilometer km + * \return + */ + static CDistanceUnit& km() { static CDistanceUnit km("kilometer", "km", true, false, CMeasurementPrefix::k().getFactor(), CMeasurementPrefix::k(), 3);return km;} + /*! + * \brief Centimeter cm + * \return + */ + static CDistanceUnit& cm() { static CDistanceUnit cm("centimeter", "cm", true, false, CMeasurementPrefix::c().getFactor(), CMeasurementPrefix::c(), 1);return cm;} +}; + +/*! + * \brief Physical unit distance + * \author KWB + */ +class CDistance : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CDistance(); + /** + *\brief downcast copy constructor + */ + CDistance(const CPhysicalQuantity &distance); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CDistance(qint32 value, const CDistanceUnit &unit = CDistanceUnit::m()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CDistance(double value, const CDistanceUnit &unit = CDistanceUnit::m()); + /*! + * \brief Unit of the distance + * \return + */ + CDistanceUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CDistanceUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace blackCore +#endif // PQDISTANCE_H diff --git a/src/blackcore/pqfrequency.cpp b/src/blackcore/pqfrequency.cpp new file mode 100644 index 000000000..d4736b705 --- /dev/null +++ b/src/blackcore/pqfrequency.cpp @@ -0,0 +1,38 @@ +#include "pqfrequency.h" + +namespace BlackCore { + +/** + * Default constructor + */ +CFrequency::CFrequency() : CPhysicalQuantity(0, CFrequencyUnit::Hz(), CFrequencyUnit::Hz()) +{ + // void +} + +/** + * Constructor + */ +CFrequency::CFrequency(const CPhysicalQuantity &frequency): CPhysicalQuantity(frequency) +{ + //void +} + +/** + * Constructor + */ +CFrequency::CFrequency(qint32 value, const CFrequencyUnit &unit) : CPhysicalQuantity(value, unit, CFrequencyUnit::Hz()) +{ + // void +} + +/** + * Constructor + */ +CFrequency::CFrequency(double value, const CFrequencyUnit &unit) : CPhysicalQuantity(value, unit, CFrequencyUnit::Hz()) +{ + // void +} + + +} // namespace diff --git a/src/blackcore/pqfrequency.h b/src/blackcore/pqfrequency.h new file mode 100644 index 000000000..ce85a6c37 --- /dev/null +++ b/src/blackcore/pqfrequency.h @@ -0,0 +1,92 @@ +#ifndef PQFREQUENCY_H +#define PQFREQUENCY_H +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for frequency (hertz, mega hertz, kilo hertz). + * \author KWB + */ +class CFrequencyUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief CFrequencyUnit + * \param name + * \param unitName + * \param isSIUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CFrequencyUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : + CMeasurementUnit(name, unitName, "frequency", isSIUnit, false, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CFrequencyUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Hertz + * \return + */ + static CFrequencyUnit& Hz() { static CFrequencyUnit Hz("hertz", "Hz", true); return Hz;} + /*! + * \brief Kilohertz + * \return + */ + static CFrequencyUnit& kHz() { static CFrequencyUnit kHz("kilohertz", "kHz", true, CMeasurementPrefix::k().getFactor(), CMeasurementPrefix::k(), 0);return kHz;} + /*! + * \brief Megahertz + * \return + */ + static CFrequencyUnit& MHz() { static CFrequencyUnit MHz("megahertz", "MHz", false, CMeasurementPrefix::M().getFactor(), CMeasurementPrefix::M(), 0); return MHz;} + /*! + * \brief Gigahertz + * \return + */ + static CFrequencyUnit& GHz() { static CFrequencyUnit GHz("gigahertz", "GHz", true, CMeasurementPrefix::G().getFactor(), CMeasurementPrefix::G(), 0);return GHz;} +}; + +/*! + * \brief Physical unit distance + * \author KWB + */ +class CFrequency : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CFrequency(); + /** + *\brief downcast copy constructor + */ + CFrequency(const CPhysicalQuantity &frequency); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CFrequency(qint32 value, const CFrequencyUnit &unit = CFrequencyUnit::Hz()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CFrequency(double value, const CFrequencyUnit &unit = CFrequencyUnit::Hz()); + /*! + * \brief Unit of the distance + * \return + */ + CFrequencyUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CFrequencyUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace blackCore +#endif // PQFREQUENCY_H diff --git a/src/blackcore/pqmass.cpp b/src/blackcore/pqmass.cpp new file mode 100644 index 000000000..0e8febaa0 --- /dev/null +++ b/src/blackcore/pqmass.cpp @@ -0,0 +1,37 @@ +#include "pqmass.h" + +namespace BlackCore { + +/** + * Default Constructor + */ +CMass::CMass(): CPhysicalQuantity(0, CMassUnit::kg(),CMassUnit::kg()) +{ + //void +} + +/** + * Constructor + */ +CMass::CMass(const CPhysicalQuantity &weight): CPhysicalQuantity(weight) +{ + // void +} + +/** + * Constructor + */ +CMass::CMass(qint32 value, const CMassUnit &unit) : CPhysicalQuantity(value, unit, CMassUnit::kg()) +{ + // void +} + +/** + * Constructor + */ +CMass::CMass(double value, const CMassUnit &unit) : CPhysicalQuantity(value, unit, CMassUnit::kg()) +{ + // void +} + +} // namespace BlackCore diff --git a/src/blackcore/pqmass.h b/src/blackcore/pqmass.h new file mode 100644 index 000000000..90f744644 --- /dev/null +++ b/src/blackcore/pqmass.h @@ -0,0 +1,94 @@ +#ifndef PQMASS_H +#define PQMASS_H +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for mass units (kg, lbs). + * \author KWB + */ +class CMassUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief Mass units + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CMassUnit(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, "mass", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CMassUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Kilogram, SI base unit + * \return + */ + static CMassUnit& kg() { static CMassUnit kg("kilogram", "kg", true, true, 1.0, CMeasurementPrefix::k(), 1); return kg;} + /*! + * \brief Gram, SI unit + * \return + */ + static CMassUnit& g() { static CMassUnit g("gram", "g", true, false, 1.0/1000.0, CMeasurementPrefix::One(), 0); return g;} + /*! + * \brief Tonne, aka metric tonne (1000kg) + * \return + */ + static CMassUnit& t() { static CMassUnit t("tonne", "t", true, false, 1000.0, CMeasurementPrefix::One(), 3); return t;} + /*! + * \brief Pound, aka mass pound + * \return + */ + static CMassUnit& lb() { static CMassUnit lbs("pound", "lb", false, false, 0.45359237, CMeasurementPrefix::One(), 1); return lbs;} +}; + +/*! + * \brief Mass + * \author KWB + */ +class CMass : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CMass(); + /** + *\brief downcast copy constructor + */ + CMass(const CPhysicalQuantity &mass); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CMass(qint32 value, const CMassUnit &unit = CMassUnit::kg()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CMass(double value, const CMassUnit &unit = CMassUnit::kg()); + /*! + * \brief Unit of the mass + * \return + */ + CMassUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CMassUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace blackCore + +#endif // PQMASS_H diff --git a/src/blackcore/pqphysicalquantity.cpp b/src/blackcore/pqphysicalquantity.cpp new file mode 100644 index 000000000..6eb07b19f --- /dev/null +++ b/src/blackcore/pqphysicalquantity.cpp @@ -0,0 +1,391 @@ +#include "pqPhysicalQuantity.h" + +namespace BlackCore { + +/** + * Constructor by integer + */ +CPhysicalQuantity::CPhysicalQuantity(qint32 baseValue, const CMeasurementUnit &unit, const CMeasurementUnit &siConversionUnit) : + _unit(unit), _conversionSiUnit(siConversionUnit) +{ + this->setUnitValue(baseValue); +} + +/** + * Constructor by double + */ +CPhysicalQuantity::CPhysicalQuantity(double baseValue, const CMeasurementUnit &unit, const CMeasurementUnit &siConversionUnit) : + _unit(unit), _conversionSiUnit(siConversionUnit) +{ + this->setUnitValue(baseValue); +} + +/** + * Copy constructor + */ +CPhysicalQuantity::CPhysicalQuantity(const CPhysicalQuantity &otherQuantity) : + _unitValueD(otherQuantity._unitValueD), _unitValueI(otherQuantity._unitValueI), _convertedSiUnitValueD(otherQuantity._convertedSiUnitValueD), + _isIntegerBaseValue(otherQuantity._isIntegerBaseValue), _unit(otherQuantity._unit), _conversionSiUnit(otherQuantity._conversionSiUnit) +{ + // void +} + +/** + * Stream operator + */ +QDebug operator <<(QDebug d, const CPhysicalQuantity &quantity) +{ + QString v = quantity.unitValueRoundedWithUnit(-1); + d << v; + return d; +} + +/** + * Equal operator == + */ +bool CPhysicalQuantity::operator ==(const CPhysicalQuantity &otherQuantity) const +{ + if(this == &otherQuantity) return true; + if(this->_unit.getType()!= otherQuantity._unit.getType()) return false; + + // some special case for best quality + double diff; + const double lenient = 1.001; // even diff alread has a round issue + if (this->_unit == otherQuantity._unit) { + // same unit + if (this->_isIntegerBaseValue && otherQuantity._isIntegerBaseValue) { + // pure integer comparison, no rounding issues + return this->_unitValueI == otherQuantity._unitValueI; + } else { + diff = abs(this->_unitValueD - otherQuantity._unitValueD); + return diff <= (lenient * this->_unit.getEpsilon()); + } + } else { + // based on SI value + diff = abs(this->_convertedSiUnitValueD - otherQuantity._convertedSiUnitValueD); + return diff <= (lenient * this->_unit.getEpsilon()); + } +} + +/** + * Not equal + */ +bool CPhysicalQuantity::operator !=(const CPhysicalQuantity &otherQuantity) const { + if(this == &otherQuantity) return false; + return !(*this == otherQuantity); +} + +/** + * Assigment operator = + */ +CPhysicalQuantity& CPhysicalQuantity::operator=(const CPhysicalQuantity &otherQuantity) { + + // Check for self-assignment! + if (this == &otherQuantity) return *this; // Same object? Yes, so skip assignment, and just return *this + + CPhysicalQuantity::_unitValueI = otherQuantity._unitValueI; + CPhysicalQuantity::_unitValueD = otherQuantity._unitValueD; + CPhysicalQuantity::_convertedSiUnitValueD = otherQuantity._convertedSiUnitValueD; + CPhysicalQuantity::_isIntegerBaseValue = otherQuantity._isIntegerBaseValue; + CPhysicalQuantity::_unit = otherQuantity._unit; + CPhysicalQuantity::_conversionSiUnit = otherQuantity._conversionSiUnit; + return *this; +} + +/** + * Plus operator + */ +CPhysicalQuantity &CPhysicalQuantity::operator +=(const CPhysicalQuantity &otherQuantity) +{ + if (this->_unit == otherQuantity._unit) { + // same unit + if (this->_isIntegerBaseValue && otherQuantity._isIntegerBaseValue) { + // pure integer, no rounding issues + this->setUnitValue(otherQuantity._unitValueI + this->_unitValueI); + } else { + this->setUnitValue(otherQuantity._unitValueI + this->_unitValueI); + } + } else { + double v = otherQuantity.value(this->_unit); + this->setUnitValue(v + this->_unitValueD); + } + return *this; +} + +/** + * Plus operator + */ +CPhysicalQuantity &CPhysicalQuantity::operator +=(double unprefixedSiUnitValue) +{ + if (!this->isUnprefixedSiUnit()) { + this->switchUnit(this->_conversionSiUnit); + } + this->setUnitValue(this->_unitValueD + unprefixedSiUnitValue); + return *this; +} + +/** + * Plus operator + */ +const CPhysicalQuantity CPhysicalQuantity::operator +(const CPhysicalQuantity &otherQuantity) const +{ + CPhysicalQuantity pq = (*this); + return pq+= otherQuantity; +} + +/** + * Minus operator + */ +CPhysicalQuantity &CPhysicalQuantity::operator -=(const CPhysicalQuantity &otherQuantity) +{ + if (this->_unit == otherQuantity._unit) { + // same unit + if (this->_isIntegerBaseValue && otherQuantity._isIntegerBaseValue) { + // pure integer, no rounding issues + this->setUnitValue(otherQuantity._unitValueI - this->_unitValueI); + } else { + this->setUnitValue(otherQuantity._unitValueI - this->_unitValueI); + } + } else { + double v = otherQuantity.value(this->_unit); + this->setUnitValue(v - this->_unitValueD); + } + return *this; +} + +/** + * Minus operator + */ +CPhysicalQuantity &CPhysicalQuantity::operator -=(double unprefixedSiUnitValue) +{ + *this += (-unprefixedSiUnitValue); + return *this; +} + +/** + * Minus operator + */ +const CPhysicalQuantity CPhysicalQuantity::operator -(const CPhysicalQuantity &otherQuantity) const +{ + CPhysicalQuantity pq = (*this); + return pq-= otherQuantity; +} + +/** + * Multiply operator + */ +CPhysicalQuantity &CPhysicalQuantity::operator *=(double multiply) +{ + this->setUnitValue(this->_unitValueD *multiply); + return *this; +} + +/** + * Multiply operator + */ +const CPhysicalQuantity CPhysicalQuantity::operator *(double multiply) const +{ + CPhysicalQuantity pq= (*this); + return pq *= multiply; +} + +/** + * Divide operator /= + */ +CPhysicalQuantity &CPhysicalQuantity::operator /=(double divide) +{ + this->setUnitValue(this->_unitValueD / divide); + return *this; +} + +/** + * Divide operator /= + */ +const CPhysicalQuantity CPhysicalQuantity::operator /(double divide) const +{ + CPhysicalQuantity pq= (*this); + return pq /= divide; +} + +/** + * Less operator < + */ +bool CPhysicalQuantity::operator <(const CPhysicalQuantity &otherQuantity) const { + if(this == &otherQuantity) return false; + double diff = this->_convertedSiUnitValueD - otherQuantity._convertedSiUnitValueD; + return (diff < 0 && abs(diff) >= this->_unit.getEpsilon()); +} + +bool CPhysicalQuantity::operator >(const CPhysicalQuantity &otherQuantity) const { + if(this == &otherQuantity) return false; + return otherQuantity < *this; +} + +bool CPhysicalQuantity::operator >=(const CPhysicalQuantity &otherQuantity) const { + if(this == &otherQuantity) return true; + return !(*this < otherQuantity); +} + +bool CPhysicalQuantity::operator <=(const CPhysicalQuantity &otherQuantity) const { + if(this == &otherQuantity) return true; + return !(*this > otherQuantity); +} + +/** + * Switch to another unit + */ +bool CPhysicalQuantity::switchUnit(const BlackCore::CMeasurementUnit &unit) +{ + if (this->_unit == unit) return true; + if (this->_unit.getType() != unit.getType()) return false; // not possible + + double cf = this->_unit.conversionFactor(unit); + this->_unit =unit; + this->setUnitValue(cf * this->_unitValueD); + return true; +} + +/** + * Init by integer + */ +void CPhysicalQuantity::setUnitValue(qint32 baseValue) +{ + this->_unitValueI= baseValue; + this->_unitValueD= double(baseValue); + this->_isIntegerBaseValue = true; + this->setConversionSiUnitValue(); +} + +/** + * Init by double + */ +void CPhysicalQuantity::setUnitValue(double baseValue) +{ + this->_unitValueD = baseValue; + this->_unitValueI = qRound(baseValue); + this->_isIntegerBaseValue = false; + this->setConversionSiUnitValue(); + +} + +/** + * @brief set SI value + */ +void CPhysicalQuantity::setConversionSiUnitValue() { + if (this->_unit == CMeasurementUnit::None()) { + this->_convertedSiUnitValueD=0.0; + } else { + double f = this->_unit.conversionFactor(this->_conversionSiUnit); + this->_convertedSiUnitValueD =f * this->_unitValueD; + } +} + +/** + * Round + */ +double CPhysicalQuantity::unitValueToDoubleRounded(int digits) const +{ + if (digits < 1) digits = this->_unit.getDisplayDigits(); + return CPhysicalQuantity::round(this->_unitValueD, digits); +} + +/** + * Rounded to QString + */ +QString CPhysicalQuantity::toQStringRounded(double value, int digits) +{ + double v =CPhysicalQuantity::round(value, digits); + QString s = QLocale::system().toString(v, 'f', digits); + return s; +} + +/** + * Rounded value to QString + */ +QString CPhysicalQuantity::unitValueToQStringRounded(int digits) const +{ + if (digits < 1) digits = this->_unit.getDisplayDigits(); + return CPhysicalQuantity::toQStringRounded(this->_unitValueD, digits); +} + +/** + * Rounded SI value to QString + */ +QString CPhysicalQuantity::convertedSiValueToQStringRounded(int digits) const +{ + if (digits < 1) digits = this->_conversionSiUnit.getDisplayDigits(); + return CPhysicalQuantity::toQStringRounded(this->_convertedSiUnitValueD, digits); +} + +/** + * Value rounded in original unit + */ +QString CPhysicalQuantity::unitValueRoundedWithUnit(int digits) const { + if (digits < 1) digits = this->_unit.getDisplayDigits(); + return this->unitValueToQStringRounded(digits).append(this->_unit.getUnitName()); +} + +/** + * SI base unit value with unit + */ +QString CPhysicalQuantity::convertedSiValueRoundedWithUnit(int digits) const { + if (digits < 1) digits = this->_conversionSiUnit.getDisplayDigits(); + return this->convertedSiValueToQStringRounded(digits).append(this->_conversionSiUnit.getUnitName()); +} + +/** + * Value rounded in unit + */ +QString CPhysicalQuantity::valueRoundedWithUnit(const CMeasurementUnit &unit, int digits) const +{ + if (unit == this->_unit) return this->unitValueRoundedWithUnit(digits); + if (unit == this->_conversionSiUnit) return this->convertedSiValueRoundedWithUnit(digits); + if (digits < 0) digits = unit.getDisplayDigits(); + return CPhysicalQuantity::toQStringRounded(this->value(unit), digits).append(unit.getUnitName()); +} + +/** + * Value rounded in unit + */ +double CPhysicalQuantity::valueRounded(const CMeasurementUnit &unit, int digits) const +{ + if (digits < 1) digits = unit.getDisplayDigits(); + return CPhysicalQuantity::round(this->value(unit),digits); +} + +/** + * Value in unit + */ +double CPhysicalQuantity::value(const CMeasurementUnit &unit) const +{ + double v; + if (unit == this->_unit) + v = this->_unitValueD; + else if (unit == this->_conversionSiUnit) + v = this->_convertedSiUnitValueD; + else + v = (this->_unit.conversionFactor(unit)) * (this->_unitValueD); + return v; +} + +/** + * Round utility method + */ +double CPhysicalQuantity::convertedSiValueToDoubleRounded(int digits) const +{ + if (digits < 1) digits = this->_conversionSiUnit.getDisplayDigits(); + return CPhysicalQuantity::round(this->_convertedSiUnitValueD, digits); +} + +/** + * Round utility method + */ +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; +} + +} // namespace BlackCore diff --git a/src/blackcore/pqphysicalquantity.h b/src/blackcore/pqphysicalquantity.h new file mode 100644 index 000000000..d5e5d93c5 --- /dev/null +++ b/src/blackcore/pqphysicalquantity.h @@ -0,0 +1,310 @@ +#ifndef PQPHYSICALQUANTITY_H +#define PQPHYSICALQUANTITY_H + +#include +#include +#include +#include "pqbase.h" + +namespace BlackCore { + +/*! + * \brief A physical quantity such as "5m", "20s", "1500ft/s" + * \author KWB + */ +class CPhysicalQuantity +{ + /*! + * Stream operator for debugging + * \brief operator << + * \param debug + * \param quantity + * \return + */ + friend QDebug operator<<(QDebug debug, const CPhysicalQuantity &quantity); + +private: + qint32 _unitValueI; //!< value backed by integer, allows sole integer arithmetic + double _unitValueD; //!< value backed by double + double _convertedSiUnitValueD; //!< SI unit value + bool _isIntegerBaseValue; //!< flag integer? / double? + +protected: + CMeasurementUnit _unit; //!< unit + CMeasurementUnit _conversionSiUnit; //!< corresponding SI base unit + + /*! + * \brief Constructor with int + * \param baseValue + * \param unit + * \param siBaseUnit + */ + CPhysicalQuantity(qint32 baseValue, const CMeasurementUnit &unit, const CMeasurementUnit &siConversionUnit); + /*! + * \brief Constructor with double + * \param baseValue + * \param unit + * \param siBaseUnit + */ + CPhysicalQuantity(double baseValue, const CMeasurementUnit &unit, const CMeasurementUnit &siConversionUnit); + /*! + * \brief Init by integer + * \param baseValue + */ + void setUnitValue(qint32 baseValue); + /*! + * \brief Init by double + * \param baseValue + */ + void setUnitValue (double baseValue); + /*! + * \brief Set the SI value + */ + void setConversionSiUnitValue(); + +public: + /*! + * \brief Copy constructor + * \param otherQuantity + */ + CPhysicalQuantity(const CPhysicalQuantity &otherQuantity); + /*! + * \brief Switch unit, e.g. feet meter + * \param unit + * \return + */ + bool switchUnit(const CMeasurementUnit &unit); + /*! + * \brief Value in SI base unit? Meter is an SI base unit, hertz not! + * \return + */ + bool isSiBaseUnit() const { return this->_unit.isSiBaseUnit(); } + /*! + * \brief Value in SI unit? Hertz is an derived SI unit, NM not! + * \return + */ + bool isSiUnit() const { return this->_unit.isSiUnit(); } + /*! + * \brief Value in unprefixed SI unit? Meter is a unprefixed, kilometer a prefixed SI Unit + * \return + */ + bool isUnprefixedSiUnit() const { return this->_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 + * @return + */ + double value(const CMeasurementUnit &unit) const; + /*! + * \brief Rounded value in unit + * \param unit + * \param digits + * @return + */ + double valueRounded(const CMeasurementUnit &unit, int digits) const; + /*! + * \brief Value to QString with unit, e.g. "5.00m" + * \param unit + * \param digits + * @return + */ + QString valueRoundedWithUnit(const CMeasurementUnit &unit, int digits = -1) const; + /*! + * \brief Value a int + * @return + */ + qint32 unitValueToInteger() const { return this->_unitValueI;} + /*! + * \brief Value a double + * @return + */ + double unitValueToDouble() const { return this->_unitValueD;} + /*! + * \brief SI value to integer + * @return + */ + qint32 siBaseUnitValueToInteger() const { return CPhysicalQuantity::round(this->_convertedSiUnitValueD,0);} + /*! + * \brief SI value to double + * @return + */ + qint32 siBaseUnitValueToDouble() const { return this->_convertedSiUnitValueD;} + /*! + * \brief Rounded value by n digits + * \param digits + * @return + */ + double unitValueToDoubleRounded(int digits = -1) const; + /*! + * \brief Rounded value by n digits + * \param digits if no value is provided, unit rounding is taken + * @return + */ + QString unitValueToQStringRounded(int digits = -1) const; + /*! + * \brief SI value as double + * \return + */ + double convertedSiValueToDouble() const { return this->_convertedSiUnitValueD;} + /*! + * \brief SI value as integer + * \return + */ + qint32 convertedSiValueToInteger() const { return (qint32)CPhysicalQuantity::round(this->_convertedSiUnitValueD,0);} + /*! + * \brief Rounded SI value by n digits + * \param digits + * @return + */ + double convertedSiValueToDoubleRounded(int digits = -1) const; + /*! + * \brief Rounded value by n digits + * \param digits if no value is provided, unit rounding is taken + * @return + */ + QString convertedSiValueToQStringRounded(int digits = -1) const; + /*! + * \brief SI Base unit value rounded + * \param digits + * @return + */ + QString convertedSiValueRoundedWithUnit(int digits = -1) const; + /*! + * \brief Cast as double + */ + operator double() const { return this->_convertedSiUnitValueD; } + /*! + * \brief Cast as QString + */ + operator QString() const { return this->unitValueRoundedWithUnit();} + /*! + * \brief Assignment operator = + * \param otherQuantity + * @return + */ + CPhysicalQuantity &operator =(const CPhysicalQuantity &otherQuantity); + /*! + * \brief Plus operator += + * \param otherQuantity + * @return + */ + CPhysicalQuantity &operator +=(const CPhysicalQuantity &otherQuantity); + /*! + * \brief Plus operator += + * \param unprefixedSiUnitValue + * @return + */ + CPhysicalQuantity &operator +=(double unprefixedSiUnitValue); + /*! + * \brief Minus operator-= + * \param otherQuantity + * @return + */ + CPhysicalQuantity &operator -=(const CPhysicalQuantity &otherQuantity); + /*! + * \brief Plus operator += + * \param unprefixedSiUnitValue + * @return + */ + CPhysicalQuantity &operator -=(double unprefixedSiUnitValue); + /*! + * \brief Plus operator + + * \param otherQuantity + * @return + */ + const CPhysicalQuantity operator +(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Minus operator - + * \param otherQuantity + * @return + */ + const CPhysicalQuantity operator -(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Multiply operator *= + * \param multiply + * @return + */ + CPhysicalQuantity &operator *=(double multiply); + /*! + * \brief Divide operator /= + * \param divide + * @return + */ + CPhysicalQuantity &operator /=(double divide); + /*! + * \brief Operator * + * \param multiply + * @return + */ + const CPhysicalQuantity operator *(double multiply) const; + /*! + * \brief Operator / + * \param divide + * @return + */ + const CPhysicalQuantity operator /(double divide) const; + /*! + * \brief Equal operator == + * \param otherQuantity + * @return + */ + bool operator==(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Not equal operator != + * \param otherQuantity + * @return + */ + bool operator!=(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Greater operator > + * \param otherQuantity + * @return + */ + bool operator >(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Less operator < + * \param otherQuantity + * @return + */ + bool operator <(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Less equal operator <= + * \param otherQuantity + * @return + */ + bool operator <=(const CPhysicalQuantity &otherQuantity) const; + /*! + * \brief Greater equal operator >= + * \param otherQuantity + * @return + */ + bool operator >=(const CPhysicalQuantity &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 +#endif // PQPHYSICALQUANTITY_H diff --git a/src/blackcore/pqpressure.cpp b/src/blackcore/pqpressure.cpp new file mode 100644 index 000000000..1a321e5df --- /dev/null +++ b/src/blackcore/pqpressure.cpp @@ -0,0 +1,38 @@ +#include "pqpressure.h" + +namespace BlackCore { + +/** + * Default constructor + */ +CPressure::CPressure() : CPhysicalQuantity(0, CPressureUnit::Pa(), CPressureUnit::Pa()) +{ + // void +} + +/** + * Constructor + */ +CPressure::CPressure(const CPhysicalQuantity &pressure): CPhysicalQuantity(pressure) +{ + //void +} + +/** + * Constructor + */ +CPressure::CPressure(qint32 value, const CPressureUnit &unit) : CPhysicalQuantity(value, unit, CPressureUnit::Pa()) +{ + // void +} + +/** + * Constructor + */ +CPressure::CPressure(double value, const CPressureUnit &unit) : CPhysicalQuantity(value, unit, CPressureUnit::Pa()) +{ + // void +} + + +} // namespace diff --git a/src/blackcore/pqpressure.h b/src/blackcore/pqpressure.h new file mode 100644 index 000000000..d3a61369a --- /dev/null +++ b/src/blackcore/pqpressure.h @@ -0,0 +1,108 @@ +#ifndef PQPRESSURE_H +#define PQPRESSURE_H + +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for pressure (psi, hPa, bar). + * \author KWB + */ +class CPressureUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief Pressure unit + * \param name + * \param unitName + * \param isSIUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CPressureUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : + CMeasurementUnit(name, unitName, "frequency", isSIUnit, false, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CPressureUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Pascal + * \return + */ + static CPressureUnit& Pa() { static CPressureUnit Pa("pascal", "Pa", true); return Pa;} + /*! + * \brief Hectopascal + * \return + */ + static CPressureUnit& hPa() { static CPressureUnit hPa("hectopascal", "hPa", true, CMeasurementPrefix::h().getFactor(), CMeasurementPrefix::h()); return hPa;} + /*! + * \brief Pounds per square inch + * \return + */ + static CPressureUnit& psi() { static CPressureUnit psi("pounds per square inch", "psi", false, 6894.8, CMeasurementPrefix::One(), 2); return psi;} + /*! + * \brief Bar + * \return + */ + static CPressureUnit& bar() { static CPressureUnit bar("bar", "bar", false, 1E5);return bar;} + /*! + * \brief Millibar, actually the same as hPa + * \return + */ + static CPressureUnit& mbar() { static CPressureUnit bar("bar", "bar", false, 1E2);return bar;} + /*! + * \brief Inch of mercury at 0°C + * \return + */ + static CPressureUnit& inHg() { static CPressureUnit inhg("Inch of mercury 0°C", "inHg", false, 3386.389);return inhg;} + /*! + * \brief Inch of mercury for flight level 29,92inHg = 1013,25mbar = 1013,25hPa + * \return + */ + static CPressureUnit& inHgFL() { static CPressureUnit inhg("Inch of mercury ", "inHg", false, 3386.5307486631);return inhg;} +}; + +/*! + * \brief Physical unit distance + * \author KWB + */ +class CPressure : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CPressure(); + /** + *\brief downcast copy constructor + */ + CPressure(const CPhysicalQuantity &frequency); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CPressure(qint32 value, const CPressureUnit &unit = CPressureUnit::Pa()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CPressure(double value, const CPressureUnit &unit = CPressureUnit::Pa()); + /*! + * \brief Unit of the distance + * \return + */ + CPressureUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CPressureUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace blackCore +#endif // PQPRESSURE_H diff --git a/src/blackcore/pqspeed.cpp b/src/blackcore/pqspeed.cpp new file mode 100644 index 000000000..f935638de --- /dev/null +++ b/src/blackcore/pqspeed.cpp @@ -0,0 +1,38 @@ +#include "pqspeed.h" + +namespace BlackCore { + +/** + * Default constructor + */ +CSpeed::CSpeed() : CPhysicalQuantity(0, CSpeedUnit::m_s(), CSpeedUnit::m_s()) +{ + // void +} + +/** + * Constructor + */ +CSpeed::CSpeed(const CPhysicalQuantity &speed): CPhysicalQuantity(speed) +{ + //void +} + +/** + * Constructor + */ +CSpeed::CSpeed(qint32 value, const CSpeedUnit &unit) : CPhysicalQuantity(value, unit, CSpeedUnit::m_s()) +{ + // void +} + +/** + * Constructor + */ +CSpeed::CSpeed(double value, const CSpeedUnit &unit) : CPhysicalQuantity(value, unit, CSpeedUnit::m_s()) +{ + // void +} + + +} // namespace diff --git a/src/blackcore/pqspeed.h b/src/blackcore/pqspeed.h new file mode 100644 index 000000000..685860935 --- /dev/null +++ b/src/blackcore/pqspeed.h @@ -0,0 +1,99 @@ +#ifndef CSPEED_H +#define CSPEED_H +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for speed units (m/s, ft/s, NM/h). + * \author KWB + */ +class CSpeedUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief CSpeedUnit + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \param mulitplier + * \param displayDigits + * \param epsilon + */ + CSpeedUnit(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, "speed", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CSpeedUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Meter/second m/s + * \return + */ + static CSpeedUnit& m_s() { static CSpeedUnit ms("meter/second", "m/s", true, false); return ms;} + /*! + * \brief Nautical miles per hour NM/h + * \return + */ + static CSpeedUnit& NM_h() { static CSpeedUnit NMh("nautical miles/hour", "NM/h", false, false, 1852.0/3600.0, CMeasurementPrefix::One(), 1);return NMh;} + /*! + * \brief Feet/second ft/s + * \return + */ + static CSpeedUnit& ft_s() { static CSpeedUnit fts("feet/seconds", "ft/s", false, false, 0.3048, CMeasurementPrefix::One(), 0); return fts;} + /*! + * \brief Feet/min ft/min + * \return + */ + static CSpeedUnit& ft_min() { static CSpeedUnit ftmin("feet/minute", "ft/min", false, false, 0.3048 / 60.0, CMeasurementPrefix::One(), 0); return ftmin;} + /*! + * \brief Kilometer/hour km/h + * \return + */ + static CSpeedUnit& km_h() { static CSpeedUnit kmh("kilometer/hour", "km/h", false, false, 1.0/3.6, CMeasurementPrefix::One(), 1);return kmh;} +}; + +/*! + * Speed class, e.g. "m/s", "NM/h", "km/h", "ft/s" + * \author KWB + */ +class CSpeed : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CSpeed(); + /** + *\brief downcast copy constructor + */ + CSpeed(const CPhysicalQuantity &speed); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CSpeed(qint32 value, const CSpeedUnit &unit = CSpeedUnit::m_s()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CSpeed(double value, const CSpeedUnit &unit = CSpeedUnit::m_s()); + /*! + * \brief Unit of the distance + * \return + */ + CSpeedUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CSpeedUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace + +#endif // CSPEED_H diff --git a/src/blackcore/pqtemperature.cpp b/src/blackcore/pqtemperature.cpp new file mode 100644 index 000000000..b8896fbf2 --- /dev/null +++ b/src/blackcore/pqtemperature.cpp @@ -0,0 +1,37 @@ +#include "pqtemperature.h" + +namespace BlackCore { + +/** + * Default Constructor + */ +CTemperature::CTemperature(): CPhysicalQuantity(0, CTemperatureUnit::K(),CTemperatureUnit::K()) +{ + //void +} + +/** + * Constructor + */ +CTemperature::CTemperature(const CPhysicalQuantity &temperature): CPhysicalQuantity(temperature) +{ + //void +} + +/** + * Constructor + */ +CTemperature::CTemperature(qint32 value, const CTemperatureUnit &unit) : CPhysicalQuantity(value, unit, CTemperatureUnit::K()) +{ + // void +} + +/** + * Constructor + */ +CTemperature::CTemperature(double value, const CTemperatureUnit &unit) : CPhysicalQuantity(value, unit, CTemperatureUnit::K()) +{ + // void +} + +} // namespace BlackCore diff --git a/src/blackcore/pqtemperature.h b/src/blackcore/pqtemperature.h new file mode 100644 index 000000000..fd5125012 --- /dev/null +++ b/src/blackcore/pqtemperature.h @@ -0,0 +1,84 @@ +#ifndef CTEMPERATURE_H +#define CTEMPERATURE_H +#include "pqphysicalquantity.h" + +namespace BlackCore { + +/*! + * Specialized class for temperatur units (kelvin, centidegree). + * \author KWB + */ +class CTemperatureUnit : public CMeasurementUnit { +public: + /*! + * Constructor + * \brief Temperature unit + * \param name + * \param unitName + * \param isSIUnit + * \param isSIBaseUnit + * \param conversionFactorToSI + * \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, "distance", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} + /*! + * Downcast copy constructor, allows to implement methods in base class + * \param otherUnit + */ + CTemperatureUnit(const CMeasurementUnit &otherUnit) : CMeasurementUnit(otherUnit) {} + /*! + * \brief Meter m + * \return + */ + static CTemperatureUnit& K() { static CTemperatureUnit K("Kelvin", "K", true, true); return K;} + /*! + * \brief Nautical miles NM + * \return + */ + static CTemperatureUnit& C() { static CTemperatureUnit C("centigrade", "°C", false, false);return C;} +}; + +/*! + * \brief Physical unit distance + * \author KWB + */ +class CTemperature : public CPhysicalQuantity +{ +public: + /*! + * \brief Default constructor + */ + CTemperature(); + /** + *\brief downcast copy constructor + */ + CTemperature(const CPhysicalQuantity &distance); + /*! + * \brief Init by int value + * \param value + * \param unit + */ + CTemperature(qint32 value, const CTemperatureUnit &unit = CTemperatureUnit::K()); + /*! + *\brief Init by double value + * \param value + * \param unit + */ + CTemperature(double value, const CTemperatureUnit &unit = CTemperatureUnit::K()); + /*! + * \brief Unit of the distance + * \return + */ + CTemperatureUnit getUnit() const { return this->_unit; } + /*! + * \brief Conversion SI unit + * \return + */ + CTemperatureUnit getConversionSiUnit() const { return this->_conversionSiUnit; } +}; +} // namespace blackCore + +#endif // CTEMPERATURE_H diff --git a/tests/blackcore/main.cpp b/tests/blackcore/main.cpp new file mode 100644 index 000000000..7810e6d67 --- /dev/null +++ b/tests/blackcore/main.cpp @@ -0,0 +1,14 @@ +#include +#include +#include "testmain.h" + +using namespace BlackCoreTest; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + TestMain::unitMain(argc, argv); + + // bye + return a.exec(); +} diff --git a/tests/blackcore/test_blackcore.pro b/tests/blackcore/test_blackcore.pro new file mode 100644 index 000000000..e8e190d88 --- /dev/null +++ b/tests/blackcore/test_blackcore.pro @@ -0,0 +1,25 @@ +QT += core testlib +QT -= gui + +TARGET = test_blackcore +TEMPLATE = app + +CONFIG += console +CONFIG -= app_bundle + +DEPENDPATH += . ../../src/blackcore +INCLUDEPATH += . ../../src/blackcore +SOURCES += main.cpp testmain.cpp testphysicalquantitiesbase.cpp +HEADERS += testmain.h testphysicalquantitiesbase.h + +win32-msvc* { + PRE_TARGETDEPS += ../../lib/blackcore.lib + LIBS += ../../lib/blackcore.lib +} + +!win32-msvc* { + PRE_TARGETDEPS += ../../lib/libblackcore.a + LIBS += ../../lib/libblackcore.a +} + +DESTDIR = ../../bin diff --git a/tests/blackcore/testmain.cpp b/tests/blackcore/testmain.cpp new file mode 100644 index 000000000..3f75a192a --- /dev/null +++ b/tests/blackcore/testmain.cpp @@ -0,0 +1,19 @@ +#include "testmain.h" + +namespace BlackCoreTest { + +//! Starting main, equivalent to QTEST_APPLESS_MAIN for multiple test classes. +/*! \param argc + \param argv + \sa http://stackoverflow.com/questions/12194256/qt-how-to-organize-unit-test-with-more-than-one-class +*/ +int TestMain::unitMain(int argc, char *argv[]) +{ + int status = 0; + { + TestPhysicalQuantitiesBase pqBaseTests ; + status |= QTest::qExec(&pqBaseTests, argc, argv); + } + return status; +} +} diff --git a/tests/blackcore/testmain.h b/tests/blackcore/testmain.h new file mode 100644 index 000000000..858fef689 --- /dev/null +++ b/tests/blackcore/testmain.h @@ -0,0 +1,25 @@ +#ifndef TESTMAIN_H +#define TESTMAIN_H + +#include +#include "testphysicalquantitiesbase.h" + +using namespace BlackCore; +using namespace BlackCoreTest; + + +namespace BlackCoreTest{ + +/*! + * Class firing of all unit tests in this namespace. + * Avoids clashes with other main(..) functions and allows to fire the test cases + * simply from any other main. + */ +class TestMain +{ +public: + static int unitMain(int argc, char *argv[]); +}; +} + +#endif // TESTMAIN_H diff --git a/tests/blackcore/testphysicalquantitiesbase.cpp b/tests/blackcore/testphysicalquantitiesbase.cpp new file mode 100644 index 000000000..c9fa06bfa --- /dev/null +++ b/tests/blackcore/testphysicalquantitiesbase.cpp @@ -0,0 +1,150 @@ +#include "testphysicalquantitiesbase.h" + +namespace BlackCoreTest { + +/*! + * \brief Constructor + * \param parent + */ +TestPhysicalQuantitiesBase::TestPhysicalQuantitiesBase(QObject *parent) : QObject(parent) +{ + // void +} + +/*! + * Basic unit tests for physical units + */ +void TestPhysicalQuantitiesBase::unitsBasics() +{ + QVERIFY(CMeasurementPrefix::k() > CMeasurementPrefix::h()); + + // some tests on units + CDistanceUnit du1 = CDistanceUnit::m(); // Copy + CDistanceUnit du2 = CDistanceUnit::m(); // Copy + QVERIFY2(du1 == du2, "Compare by value 1"); + du1 = CDistanceUnit::m(); // Copy + du2 = CDistanceUnit::m(); // Copy + QVERIFY2(du1 == du2, "Compare by value 2"); + QVERIFY2(CDistanceUnit::m() == CDistanceUnit::m(), "Compare by value"); + QVERIFY2(CMeasurementPrefix::h() < CMeasurementPrefix::M(), "hecto < mega"); + + CFrequencyUnit fu1 = CFrequencyUnit::Hz(); + QVERIFY2(fu1 != du1, "Hz must not be meter"); +} + +/*! + * Distance tests + */ +void TestPhysicalQuantitiesBase::distanceBasics() +{ + CDistance d1(1); // 1m + CDistance d2(100, CDistanceUnit::cm()); + CDistance d3(1.852 * 1000); // 1852m + CDistance d4(1,CDistanceUnit::NM()); + + QVERIFY2(d1 == d2, "1meter shall be 100cm"); + QVERIFY2(d3 == d4, "1852meters shall be 1NM"); + + d3 *=2; // SI value + d4 *=2.0; // SI value ! + QVERIFY2(d3 == d4, "2*1852meters shall be 2NM"); + + // less / greater + QVERIFY2(!(d1 < d2), "Nothing shall be less / greater"); + QVERIFY2(!(d1 > d2), "Nothing shall be less / greater"); + + // epsilon tests + d1 += d1.getUnit().getEpsilon(); // this should be still the same + QVERIFY2(d1 == d2, "Epsilon: 1meter+epsilon shall be 100cm"); + QVERIFY2(!(d1 != d2), "Epsilon: 1meter+epsilon shall be 100cm"); + + d1 += d1.getUnit().getEpsilon(); // now over epsilon threshold + QVERIFY2(d1 != d2, "Epsilon exceeded: 1meter+2epsilon shall not be 100cm"); + QVERIFY2(d1 > d2, "d1 shall be greater"); +} + +/** + * Unit tests for speed + */ +void TestPhysicalQuantitiesBase::speedBasics() +{ + CSpeed s1(100, CSpeedUnit::km_h()); + CSpeed s2(1000, CSpeedUnit::ft_min()); + QVERIFY2(s1.valueRounded(CSpeedUnit::NM_h(),0) == 54, "100km/h is 54NM/h"); + QVERIFY2(s2.valueRounded(CSpeedUnit::m_s(),1) == 5.1, "1000ft/min is 5.1m/s"); +} + +/** + * Frequency unit tests + */ +void TestPhysicalQuantitiesBase::frequencyTests() +{ + CFrequency f1(1, CFrequencyUnit::MHz()); + QVERIFY2(f1.valueRounded(CFrequencyUnit::kHz(),2) == 1000, "Mega is 1000kHz"); + QVERIFY2(f1 == 1000000 , "MHz is 1E6 Hz"); + CFrequency f2 = CMeasurementPrefix::M(); // 1 Megahertz + QVERIFY2(f1 == f2 , "MHz is 1E6 Hz"); +} + +/** + * Angle tests + */ +void TestPhysicalQuantitiesBase::angleTests() +{ + CAngle a1(180, CAngleUnit::deg()); + CAngle a2(1.5 * CAngle::pi()); + a2.switchUnit(CAngleUnit::deg()); + QVERIFY2(a2.unitValueToInteger() == 270, "1.5Pi should be 270deg"); + QVERIFY2(a1.piFactor() == 1, "Pi should be 180deg"); +} + +/** + * Weight tests + */ +void TestPhysicalQuantitiesBase::massTests() +{ + CMass w1(1000); + CMass w2(w1); + w2.switchUnit(CMassUnit::t()); + QVERIFY2(w2.unitValueToInteger() == 1, "1tonne shall be 1000kg"); + w2.switchUnit(CMassUnit::lb()); + QVERIFY2(w2.unitValueToDoubleRounded(2) == 2204.62, "1tonne shall be 2204pounds"); + QVERIFY2(w1 == w2, "Masses shall be equal"); +} + +/** + * Pressure tests + */ +void TestPhysicalQuantitiesBase::pressureTests() +{ + CPressure p1(1013.25, CPressureUnit::hPa()); + CPressure p2(29.92,CPressureUnit::inHg()); + CPressure p3(29.92,CPressureUnit::inHgFL()); + CPressure p4(p1); + p4.switchUnit(CPressureUnit::mbar()); + + // does not match exactly + QVERIFY2(p1 != p2, "Standard pressure test little difference"); + QVERIFY2(p1 == p3, "Standard pressure test matching"); + QVERIFY2(p1.unitValueToDouble() == p4.unitValueToDouble(), "mbar/hPa test"); +} + +/** + * @brief Just tesing obvious memory create / destruct flaws + */ +void TestPhysicalQuantitiesBase::memoryTests() +{ + CDistance* c = new CDistance(100); + c->switchUnit(CDistanceUnit::NM()); + QVERIFY2(c->getUnit() == CDistanceUnit::NM() && c->getConversionSiUnit() == CDistanceUnit::m(), + "Testing distance units failed"); + delete c; + + CAngle* a = new CAngle(100); + a->switchUnit(CAngleUnit::deg()); + QVERIFY2(a->getUnit() == CAngleUnit::deg() && c->getConversionSiUnit() == CAngleUnit::rad(), + "Testing angle units failed"); + delete a; +} + +} // namespace diff --git a/tests/blackcore/testphysicalquantitiesbase.h b/tests/blackcore/testphysicalquantitiesbase.h new file mode 100644 index 000000000..0aa20b669 --- /dev/null +++ b/tests/blackcore/testphysicalquantitiesbase.h @@ -0,0 +1,66 @@ +#ifndef TESTPHYSICALQUANTITIESBASE_H +#define TESTPHYSICALQUANTITIESBASE_H + +#include +#include "../../src/blackcore/pqdistance.h" +#include "../../src/blackcore/pqfrequency.h" +#include "../../src/blackcore/pqspeed.h" +#include "../../src/blackcore/pqangle.h" +#include "../../src/blackcore/pqmass.h" +#include "../../src/blackcore/pqpressure.h" +using namespace BlackCore; + +namespace BlackCoreTest { + +/*! + * \brief Physical quantities,basic tests + */ +class TestPhysicalQuantitiesBase : public QObject +{ + Q_OBJECT +public: + /*! + * \brief Standard test case constructor + * \param parent + */ + explicit TestPhysicalQuantitiesBase(QObject *parent = 0); +private slots: + /*! + * \brief Basic unit tests for physical units + */ + void unitsBasics(); + /*! + * \brief Basic tests around distance + */ + void distanceBasics(); + /*! + * \brief Basic tests about speed + */ + void speedBasics(); + /*! + * \brief Frequency tests + */ + void frequencyTests(); + /*! + * \brief Testing angles (degrees / radians) + */ + void angleTests(); + /*! + * \brief Testing angles + */ + void massTests(); + /*! + * \brief Testing pressure + */ + void pressureTests(); + + /*! + * \brief testing construction / destruction in memory + */ + void memoryTests(); + +}; + +} + +#endif // TESTPHYSICALQUANTITIESBASE_H