First major wave of PQ refactoring, including but not limited to:

* Default unit is more clearly stated in one place, not restated in many different places, and is not always the SI unit
* Converter strategy pattern in CMeasurementUnit, covering linear, affine, and different kinds of sexagesimal units
* General reorganization of CMeasurementUnit construction and CPhysicalQuantity methods, not removing any behvaiour
* Move duplicated method unitFromSymbol from derived classes into base class CMeasurementUnit
* For DBus, CPhysicalQuantity marshals both in its own unit and in the default unit
This commit is contained in:
Mathew Sutcliffe
2013-08-18 23:40:52 +01:00
parent a8036f1ce5
commit da8ba9aac3
26 changed files with 809 additions and 957 deletions

View File

@@ -57,7 +57,7 @@ int CSamplesPhysicalQuantities::samples()
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() << s1 << s1.valueRoundedWithUnit(CSpeedUnit::defaultUnit()) << s1.valueRoundedWithUnit(CSpeedUnit::NM_h());
qDebug() << s2 << s3;
CAngle a1(180, CAngleUnit::deg());
@@ -72,7 +72,7 @@ int CSamplesPhysicalQuantities::samples()
a2 = a1 + a1;
a2.switchUnit(CAngleUnit::deg());
qDebug() << a1.unitValueRoundedWithUnit() << a1.piFactor();
qDebug() << a1.valueRoundedWithUnit() << a1.piFactor();
qDebug() << a2;
a3.switchUnit(CAngleUnit::sexagesimalDeg());
a4.switchUnit(CAngleUnit::deg());
@@ -89,8 +89,8 @@ int CSamplesPhysicalQuantities::samples()
CTemperature t1;
CTemperature t2(20, CTemperatureUnit::C());
CTemperature t3(1, CTemperatureUnit::F());
qDebug() << t1 << t2 << t2.convertedSiValueRoundedWithUnit(true);
qDebug() << t3.valueRoundedWithUnit(CTemperatureUnit::F(), -1 ,true) << t3.valueRoundedWithUnit(CTemperatureUnit::C(), -1, true) << "I18N/UTF";
qDebug() << t1 << t2 << t2.valueRoundedWithUnit(CTemperatureUnit::defaultUnit(), -1, true);
qDebug() << t3.valueRoundedWithUnit(CTemperatureUnit::F(), -1, true) << t3.valueRoundedWithUnit(CTemperatureUnit::C(), -1, true) << "I18N/UTF";
// some logging with CLogMessage
// bDebug << p1;
@@ -108,10 +108,13 @@ int CSamplesPhysicalQuantities::samples()
CTime ti1(1, CTimeUnit::h());
CTime ti2(ti1);
ti2.switchUnit(CTimeUnit::ms());
qDebug() << ti1 << ti2;
CTime ti3(1.0101, CTimeUnit::hms());
CTime ti4(1.15, CTimeUnit::hrmin());
CTime ti5(1.30, CTimeUnit::minsec());
qDebug() << ti1 << ti2 << ti3 << ti4 << ti5;
CAcceleration ac1(10, CAccelerationUnit::m_s2());
qDebug() << ac1 << ac1.unitValueRoundedWithUnit(-1, true) << "I18N/UTF";
qDebug() << ac1 << ac1.valueRoundedWithUnit(-1, true) << "I18N/UTF";
// bye
qDebug() << "-----------------------------------------------";

View File

@@ -114,7 +114,7 @@ int main(int argc, char *argv[])
qDebug() << "Send speed via interface" << speed;
TestserviceTool::sleep(2500);
speed.switchUnit(CSpeedUnit::km_h());
speed.addUnitValue(1.0);
speed.addValueSameUnit(1.0);
// Aviation
CComSystem comSystem = CComSystem("DBUS COM1", CPhysicalQuantitiesConstants::FrequencyInternationalAirDistress(), CPhysicalQuantitiesConstants::FrequencyUnicom());
@@ -125,7 +125,7 @@ int main(int argc, char *argv[])
testserviceInterface.receiveVariant(qv);
testserviceInterface.receiveAltitude(al);
qDebug() << "Send altitude via interface" << al;
al.addUnitValue(1);
al.addValueSameUnit(1);
CTransponder transponder("transponder", 7000, CTransponder::ModeC);
testserviceInterface.receiveTransponder(transponder);

View File

@@ -85,8 +85,8 @@ protected:
virtual QString convertToQString(bool i18n = false) const
{
QString s(this->getName());
s.append(" Active: ").append(this->m_frequencyActive.unitValueRoundedWithUnit(3, i18n));
s.append(" Standby: ").append(this->m_frequencyStandby.unitValueRoundedWithUnit(3, i18n));
s.append(" Active: ").append(this->m_frequencyActive.valueRoundedWithUnit(3, i18n));
s.append(" Standby: ").append(this->m_frequencyStandby.valueRoundedWithUnit(3, i18n));
return s;
}

View File

@@ -16,7 +16,7 @@ namespace Geo
QString CCoordinateGeodetic::convertToQString(bool i18n) const
{
QString s = "Geodetic: {%1, %2, %3}";
return s.arg(this->m_latitude.unitValueRoundedWithUnit(6, i18n)).arg(this->m_longitude.unitValueRoundedWithUnit(6, i18n)).arg(this->m_height.unitValueRoundedWithUnit(i18n));
return s.arg(this->m_latitude.valueRoundedWithUnit(6, i18n)).arg(this->m_longitude.valueRoundedWithUnit(6, i18n)).arg(this->m_height.valueRoundedWithUnit(i18n));
}
/*

View File

@@ -80,7 +80,7 @@ CCoordinateEcef CCoordinateTransformation::toEcef(const CCoordinateGeodetic &geo
double clambda = cos(lambdaRad);
double h = geo.height().convertedSiValueToDouble();
double h = geo.height().value(CLengthUnit::m());
double x = (n + h) * cphi;
double y = x * slambda;
x *= clambda;

View File

@@ -75,7 +75,7 @@ protected:
*/
virtual QString convertToQString() const
{
return this->unitValueRoundedWithUnit(6);
return this->valueRoundedWithUnit(6);
}
/*!

View File

@@ -6,6 +6,7 @@
#ifndef BLACKMISC_MATHEMATICS_H
#define BLACKMISC_MATHEMATICS_H
#include <QtCore/qmath.h>
#include <cmath>
namespace BlackMisc
{
@@ -70,6 +71,26 @@ public:
*/
static double roundEpsilon(double value, double epsilon);
/*!
* \brief Nearest integer not greater in magnitude than value, correcting for epsilon
* \param value
* \param epsilon
*/
static inline double trunc(double value, double epsilon = 1e-10)
{
return value < 0 ? ceil(value - epsilon) : floor(value + epsilon);
}
/*!
* \brief Fractional part of value
* \param value
*/
static inline double fract(double value)
{
double unused;
return modf(value, &unused);
}
/*!
* \brief PI
* \return

View File

@@ -21,14 +21,14 @@ public:
/*!
* \brief Default constructor
*/
CAcceleration() : CPhysicalQuantity(0, CAccelerationUnit::m_s2(), CAccelerationUnit::m_s2()) {}
CAcceleration() : CPhysicalQuantity(0, CAccelerationUnit::defaultUnit()) {}
/*!
* \brief Init by double value
* \param value
* \param unit
*/
CAcceleration(double value, const CAccelerationUnit &unit) : CPhysicalQuantity(value, unit, CAccelerationUnit::m_s2()) {}
CAcceleration(double value, const CAccelerationUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Copy constructor by base type

View File

@@ -22,7 +22,7 @@ public:
/*!
* \brief Default constructor
*/
CAngle() : CPhysicalQuantity(0, CAngleUnit::rad(), CAngleUnit::rad()) {}
CAngle() : CPhysicalQuantity(0, CAngleUnit::defaultUnit()) {}
/*!
* \brief Copy constructor from base type
@@ -34,18 +34,30 @@ public:
* \param value
* \param unit
*/
CAngle(double value, const CAngleUnit &unit): CPhysicalQuantity(value, unit, CAngleUnit::rad()) {}
CAngle(double value, const CAngleUnit &unit): CPhysicalQuantity(value, unit) {}
/*!
* \brief Intir as sexagesimal degrees
* \brief Init as sexagesimal degrees, minutes, seconds
* The sign of all parameters must be the same, either all positive or all negative.
* \param degrees
* \param minutes
* \param seconds
*/
CAngle(qint32 degrees, qint32 minutes, double seconds) :
CAngle(int degrees, int minutes, double seconds) :
CPhysicalQuantity(
degrees + minutes / 100.0 + seconds / 10000.0,
CAngleUnit::sexagesimalDeg(), CAngleUnit::rad()) {}
CAngleUnit::sexagesimalDeg()) {}
/*!
* \brief Init as sexagesimal degrees, minutes
* The sign of both parameters must be the same, either both positive or both negative.
* \param degrees
* \param minutes
*/
CAngle(int degrees, double minutes) :
CPhysicalQuantity(
degrees + minutes / 100.0,
CAngleUnit::sexagesimalDegMin()) {}
/*!
* \brief Virtual destructor
@@ -58,7 +70,7 @@ public:
*/
double piFactor() const
{
return BlackMisc::Math::CMath::round(this->convertedSiValueToDouble() / BlackMisc::Math::CMath::PI() , 6);
return BlackMisc::Math::CMath::round(this->value(CAngleUnit::rad()) / BlackMisc::Math::CMath::PI() , 6);
}
/*!

View File

@@ -14,14 +14,14 @@ namespace PhysicalQuantities
{
// -----------------------------------------------------------------------
// --- Mulitplier --------------------------------------------------------
// --- Prefix ------------------------------------------------------------
// -----------------------------------------------------------------------
/*
* Constructor
*/
CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitName, double factor) :
m_name(name), m_prefix(unitName), m_factor(factor)
CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &symbol, double factor) :
m_name(name), m_symbol(symbol), m_factor(factor)
{
}
@@ -29,7 +29,7 @@ CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitN
* Constructor
*/
CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &other) :
m_name(other.m_name), m_prefix(other.m_prefix), m_factor(other.m_factor)
m_name(other.m_name), m_symbol(other.m_symbol), m_factor(other.m_factor)
{
}
@@ -40,7 +40,7 @@ CMeasurementPrefix &CMeasurementPrefix::operator=(const CMeasurementPrefix &othe
{
if (this == &other) return *this;
this->m_name = other.m_name;
this->m_prefix = other.m_prefix;
this->m_symbol= other.m_symbol;
this->m_factor = other.m_factor;
return *this;
}
@@ -62,22 +62,6 @@ bool CMeasurementPrefix::operator !=(const CMeasurementPrefix &other) const
return !(*this == other);
}
/*
* Greater?
*/
bool CMeasurementPrefix::operator >(const CMeasurementPrefix &other) const
{
return this->m_factor > other.m_factor;
}
/*
* Less?
*/
bool CMeasurementPrefix::operator <(const CMeasurementPrefix &other) const
{
return this->m_factor < other.m_factor;
}
// -----------------------------------------------------------------------
// --- Measurement unit --------------------------------------------------
// -----------------------------------------------------------------------
@@ -85,22 +69,40 @@ bool CMeasurementPrefix::operator <(const CMeasurementPrefix &other) const
/*
* 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,
UnitConverter toSiConverter, UnitConverter fromSiConverter):
m_name(name), m_unitName(unitName), m_type(type), m_isSiUnit(isSIUnit), m_isSiBaseUnit(isSIBaseUnit),
m_conversionFactorToSIConversionUnit(conversionFactorToSI),
m_epsilon(epsilon), m_displayDigits(displayDigits), m_multiplier(multiplier), m_fromSiConverter(fromSiConverter), m_toSiConverter(toSiConverter)
CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &symbol, double factor, qint32 displayDigits, double epsilon) :
m_name(name), m_symbol(symbol), m_epsilon(epsilon), m_displayDigits(displayDigits), m_prefix(CMeasurementPrefix::One()), m_converter(new LinearConverter(factor))
{
}
/*
* Constructor
*/
CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &symbol, double factor, double offset, qint32 displayDigits, double epsilon) :
m_name(name), m_symbol(symbol), m_epsilon(epsilon), m_displayDigits(displayDigits), m_prefix(CMeasurementPrefix::One()), m_converter(new AffineConverter(factor, offset))
{
}
/*
* Constructor
*/
CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &symbol, Converter *converter, qint32 displayDigits, double epsilon) :
m_name(name), m_symbol(symbol), m_epsilon(epsilon), m_displayDigits(displayDigits), m_prefix(CMeasurementPrefix::One()), m_converter(converter)
{
}
/*
* Constructor
*/
CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &base, const CMeasurementPrefix &prefix, qint32 displayDigits, double epsilon) :
m_name(base.m_name), m_symbol(base.m_symbol), m_epsilon(epsilon), m_displayDigits(displayDigits), m_prefix(prefix), m_converter(base.m_converter->clone(prefix))
{
}
/*
* Copy constructor
*/
CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &other):
m_name(other.m_name), m_unitName(other.m_unitName), m_type(other.m_type), m_isSiUnit(other.m_isSiUnit),
m_isSiBaseUnit(other.m_isSiBaseUnit), m_conversionFactorToSIConversionUnit(other.m_conversionFactorToSIConversionUnit),
m_epsilon(other.m_epsilon), m_displayDigits(other.m_displayDigits), m_multiplier(other.m_multiplier), m_fromSiConverter(other.m_fromSiConverter), m_toSiConverter(other.m_toSiConverter)
CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &other) :
m_name(other.m_name), m_symbol(other.m_symbol), m_epsilon(other.m_epsilon), m_displayDigits(other.m_displayDigits), m_prefix(other.m_prefix), m_converter(other.m_converter)
{
}
@@ -111,16 +113,11 @@ CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &other)
{
if (this == &other) return *this; // Same object? Yes, so skip assignment, and just return *this
this->m_name = other.m_name;
this->m_unitName = other.m_unitName;
this->m_type = other.m_type;
this->m_isSiUnit = other.m_isSiUnit;
this->m_isSiBaseUnit = other.m_isSiBaseUnit;
this->m_conversionFactorToSIConversionUnit = other.m_conversionFactorToSIConversionUnit;
this->m_multiplier = other.m_multiplier;
this->m_symbol = other.m_symbol;
this->m_prefix = other.m_prefix;
this->m_displayDigits = other.m_displayDigits;
this->m_epsilon = other.m_epsilon;
this->m_fromSiConverter = other.m_fromSiConverter;
this->m_toSiConverter = other.m_toSiConverter;
this->m_converter = other.m_converter;
return *this;
}
@@ -130,9 +127,7 @@ CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &other)
bool CMeasurementUnit::operator ==(const CMeasurementUnit &other) const
{
if (this == &other) return true;
if (this->m_type != other.m_type) return false;
return this->m_multiplier == other.m_multiplier && this->m_name == other.m_name
&& this->m_isSiUnit == other.m_isSiUnit;
return this->m_prefix == other.m_prefix && this->m_name == other.m_name;
}
/*
@@ -144,28 +139,29 @@ bool CMeasurementUnit::operator !=(const CMeasurementUnit &other) const
}
/*
* Conversion factor from unit x to y
* Conversion
*/
double CMeasurementUnit::conversionToUnit(double value, const CMeasurementUnit &to) const
double CMeasurementUnit::convertFrom(double value, const CMeasurementUnit &unit) const
{
if (to == *this) return value;
double siValue = this->convertToSiConversionUnit(value);
return to.convertFromSiConversionUnit(siValue);
Q_ASSERT(this->m_converter);
Q_ASSERT(unit.m_converter);
if (this->m_converter == unit.m_converter) return value;
return this->m_converter->fromDefault(unit.m_converter->toDefault(value));
}
/*
* Value to QString with unit, e.g. "5.00m"
* @return
*/
QString CMeasurementUnit::valueRoundedWithUnit(double value, int digits, bool i18n) const
QString CMeasurementUnit::makeRoundedQStringWithUnit(double value, int digits, bool i18n) const
{
return this->toQStringRounded(value, digits).append(this->getUnitName(i18n));
return this->makeRoundedQString(value, digits).append(this->getSymbol(i18n));
}
/*
* Value rounded
*/
double CMeasurementUnit::valueRounded(double value, int digits) const
double CMeasurementUnit::roundValue(double value, int digits) const
{
if (digits < 0) digits = this->m_displayDigits;
return CMath::round(value, digits);
@@ -174,7 +170,7 @@ double CMeasurementUnit::valueRounded(double value, int digits) const
/*
* Rounded to QString
*/
QString CMeasurementUnit::toQStringRounded(double value, int digits, bool /* i18n */) const
QString CMeasurementUnit::makeRoundedQString(double value, int digits, bool /* i18n */) const
{
if (digits < 0) digits = this->m_displayDigits;
double v = CMath::round(value, digits);
@@ -182,17 +178,5 @@ QString CMeasurementUnit::toQStringRounded(double value, int digits, bool /* i18
return s;
}
/*
* Epsilon rounding
*/
double CMeasurementUnit::epsilonUpRounding(double value) const
{
// Rounds a little up in order to avoid fractions
double eps = value > 0 ? this->m_epsilon : -1.0 * this->m_epsilon;
double v = floor((value + eps) / this->m_epsilon);
v *= this->m_epsilon;
return v;
}
} // namespace
} // namespace

View File

@@ -8,12 +8,14 @@
#include "blackmisc/basestreamstringifier.h"
#include "blackmisc/debug.h"
#include "blackmisc/mathematics.h"
#include <QCoreApplication>
#include <QDBusArgument>
#include <QString>
#include <QtGlobal>
#include <QDebug>
#include <QSharedData>
#include <QSharedDataPointer>
namespace BlackMisc
{
@@ -23,13 +25,13 @@ namespace PhysicalQuantities
/*!
* \brief Typical prefixes (multipliers) such as kilo, mega, hecto.
* See <a href="http://www.poynton.com/notes/units/index.html">here</a> for an overview.
* Use the static values such CMeasurementMultiplier::k() as to specify values.
* Use the static values such as CMeasurementPrefix::k() to specify values.
*/
class CMeasurementPrefix : public CBaseStreamStringifier
{
private:
QString m_name; //!< name, e.g. "kilo"
QString m_prefix; //!< prefix, e.g. "k" for kilo
QString m_symbol; //!< prefix, e.g. "k" for kilo
double m_factor; //!< factor, e.g. 1000 for kilo 1/100 for centi
/*!
@@ -39,11 +41,11 @@ private:
* \param prefixName
* \param factor
*/
CMeasurementPrefix(const QString &name, const QString &prefixName, double factor);
CMeasurementPrefix(const QString &name, const QString &symbol, double factor);
protected:
/*!
* \brief Name as stringification
* \brief Name as string
* \param i18n
* \return
*/
@@ -100,20 +102,6 @@ public:
*/
bool operator != (const CMeasurementPrefix &other) const;
/*!
* \brief Greater operator >
* \param other
* \return
*/
bool operator > (const CMeasurementPrefix &other) const;
/*!
* \brief Less operator <
* \param other
* \return
*/
bool operator < (const CMeasurementPrefix &other) const;
/*!
* \brief Factor, e.g.1000 for "kilo"
* \return
@@ -136,26 +124,18 @@ public:
* \brief Name, e.g. "kilo"
* \return
*/
QString getName() const
QString getName(bool i18n = false) const
{
return this->m_name;
return i18n ? QCoreApplication::translate("CMeasurementPrefix", this->m_name.toStdString().c_str()) : this->m_name;
}
/*!
* \brief Prefix, e.g. "k" for "kilo"
* \return
*/
QString getPrefix() const
QString getSymbol(bool i18n = false) const
{
return this->m_prefix;
}
/*!
* \brief Operator as double
*/
operator double() const
{
return this->m_factor;
return i18n ? QCoreApplication::translate("CMeasurementPrefix", this->m_symbol.toStdString().c_str()) : this->m_symbol;
}
// --- static units, always use these for initialization
@@ -178,7 +158,7 @@ public:
*/
static const CMeasurementPrefix &One()
{
static CMeasurementPrefix one("one", "", 1.0);
static CMeasurementPrefix one(QT_TR_NOOP("one"), "", 1.0);
return one;
}
@@ -188,7 +168,7 @@ public:
*/
static const CMeasurementPrefix &M()
{
static CMeasurementPrefix mega("mega", "M", 1E6);
static CMeasurementPrefix mega(QT_TR_NOOP("mega"), "M", 1E6);
return mega;
}
@@ -198,7 +178,7 @@ public:
*/
static const CMeasurementPrefix &k()
{
static CMeasurementPrefix kilo("kilo", "k", 1000.0);
static CMeasurementPrefix kilo(QT_TR_NOOP("kilo"), "k", 1000.0);
return kilo;
}
@@ -208,7 +188,7 @@ public:
*/
static const CMeasurementPrefix &G()
{
static CMeasurementPrefix giga("giga", "G", 1E9);
static CMeasurementPrefix giga(QT_TR_NOOP("giga"), "G", 1E9);
return giga;
}
@@ -218,7 +198,7 @@ public:
*/
static const CMeasurementPrefix &h()
{
static CMeasurementPrefix hecto("hecto", "h", 100.0);
static CMeasurementPrefix hecto(QT_TR_NOOP("hecto"), "h", 100.0);
return hecto;
}
@@ -228,7 +208,7 @@ public:
*/
static const CMeasurementPrefix &c()
{
static CMeasurementPrefix centi("centi", "c", 0.01);
static CMeasurementPrefix centi(QT_TR_NOOP("centi"), "c", 0.01);
return centi;
}
@@ -238,7 +218,7 @@ public:
*/
static const CMeasurementPrefix &m()
{
static CMeasurementPrefix milli("milli", "m", 1E-03);
static CMeasurementPrefix milli(QT_TR_NOOP("milli"), "m", 1E-03);
return milli;
}
@@ -287,46 +267,171 @@ public:
/*!
* \brief Base class for all units, such as meter, hertz.
*/
class CMeasurementUnit: public CBaseStreamStringifier
class CMeasurementUnit : public CBaseStreamStringifier
{
protected:
/*!
* \brief Points to an individual converter method
* Conversion as perobject, as required for CAnglewith sexagesimal conversion
* Abstract strategy pattern that encapsulates a unit conversion strategy.
*/
typedef double(*UnitConverter)(const CMeasurementUnit &, double);
class Converter : public QSharedData
{
public:
/*!
* Virtual destructor.
*/
virtual ~Converter() {}
/*!
* Convert from this unit to default unit.
* \param factor
* \return
*/
virtual double toDefault(double factor) const = 0;
/*!
* Convert from default unit to this unit.
* \param factor
* \return
*/
virtual double fromDefault(double factor) const = 0;
/*!
* Make a copy of this object with a different prefix.
* \param prefix
* \return
*/
virtual Converter *clone(const CMeasurementPrefix &prefix) const = 0;
};
/*!
* Concrete strategy pattern for converting unit with linear conversion.
*/
class LinearConverter : public Converter
{
double m_factor;
public:
/*!
* Constructor
* \param factor
*/
LinearConverter(double factor) : m_factor(factor) {}
virtual double toDefault(double factor) const { return factor * m_factor; }
virtual double fromDefault(double factor) const { return factor / m_factor; }
virtual Converter *clone(const CMeasurementPrefix &prefix) const { auto ret = new LinearConverter(*this); ret->m_factor *= prefix.getFactor(); return ret; }
};
/*!
* Concrete strategy pattern for converting unit with affine conversion.
*/
class AffineConverter : public Converter
{
double m_factor;
double m_offset;
public:
/*!
* Constructor
* \param factor
* \param offset
*/
AffineConverter(double factor, double offset) : m_factor(factor), m_offset(offset) {}
virtual double toDefault(double factor) const { return (factor - m_offset) * m_factor; }
virtual double fromDefault(double factor) const { return factor / m_factor + m_offset; }
virtual Converter *clone(const CMeasurementPrefix &prefix) const { auto ret = new AffineConverter(*this); ret->m_factor *= prefix.getFactor(); return ret; }
};
/*!
* Concrete strategy pattern for converting unit with subdivision conversion.
*/
template <int Num, int Den>
class SubdivisionConverter : public Converter
{
double m_factor;
public:
/*!
* Constructor
*/
SubdivisionConverter(double factor = 1) : m_factor(factor) {}
virtual double toDefault(double factor) const { using BlackMisc::Math::CMath;
double ret = CMath::trunc(factor); factor = CMath::fract(factor) * Den;
ret += factor / Num;
return ret * m_factor; }
virtual double fromDefault(double factor) const { using BlackMisc::Math::CMath;
factor /= m_factor;
double ret = CMath::trunc(factor); factor = CMath::fract(factor) * Num;
return ret += factor / Den; }
virtual Converter *clone(const CMeasurementPrefix &) const { qFatal("Not implemented"); return 0; }
};
/*!
* Concrete strategy pattern for converting unit with subdivision conversion.
*/
template <int Num1, int Den1, int Num2, int Den2>
class SubdivisionConverter2 : public Converter
{
double m_factor;
public:
/*!
* Constructor
*/
SubdivisionConverter2(double factor = 1) : m_factor(factor) {}
virtual double toDefault(double factor) const { using BlackMisc::Math::CMath;
double ret = CMath::trunc(factor); factor = CMath::fract(factor) * Den1;
ret += CMath::trunc(factor) / Num1; factor = CMath::fract(factor) * Den2;
ret += factor / (Num1 * Num2);
return ret * m_factor; }
virtual double fromDefault(double factor) const { using BlackMisc::Math::CMath;
factor /= m_factor;
double ret = CMath::trunc(factor); factor = CMath::fract(factor) * Num1;
ret += CMath::trunc(factor) / Den1; factor = CMath::fract(factor) * Num2;
return ret += factor / (Den1 * Den2); }
virtual Converter *clone(const CMeasurementPrefix &) const { qFatal("Not implemented"); return 0; }
};
private:
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)
QString m_symbol; //!< unit name, e.g. "m"
double m_epsilon; //!< values with differences below epsilon are the equal
int m_displayDigits; //!< standard rounding for string conversions
CMeasurementPrefix m_multiplier; //!< multiplier (kilo, Mega)
UnitConverter m_fromSiConverter; //! allows an arbitrary conversion method as per object (e.g. angle, sexagesimal)
UnitConverter m_toSiConverter; //! allows an arbitrary conversion method as per object (e.g. angle, sexagesimal)
CMeasurementPrefix m_prefix; //!< multiplier (kilo, Mega)
QSharedDataPointer<Converter> m_converter; //!< strategy pattern allows an arbitrary conversion method as per object
protected:
/*!
* Constructor by parameter
* Construct a unit with linear conversion
* \param name
* \param unitName
* \param type
* \param isSiUnit
* \param isSiBaseUnit
* \param conversionFactorToSI
* \param multiplier
* \param symbol
* \param factor
* \param displayDigits
* \param epsilon
* \param toSiConverter
* \param fromSiConverter
*/
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, UnitConverter toSiConverter = 0, UnitConverter fromSiConverter = 0);
CMeasurementUnit(const QString &name, const QString &symbol, double factor, int displayDigits, double epsilon);
/*!
* Construct a unit with affine conversion
* \param name
* \param symbol
* \param factor
* \param offset
* \param displayDigits
* \param epsilon
*/
CMeasurementUnit(const QString &name, const QString &symbol, double factor, double offset, int displayDigits, double epsilon);
/*!
* Construct a unit with custom conversion
* \param name
* \param symbol
* \param converter
* \param displayDigits
* \param epsilon
*/
CMeasurementUnit(const QString &name, const QString &symbol, Converter *converter, int displayDigits, double epsilon);
/*!
* Construct from base unit and prefix
* \param base
* \param prefix
* \param displayDigits
* \param epsilon
*/
CMeasurementUnit(const CMeasurementUnit &base, const CMeasurementPrefix &prefix, int displayDigits = 2, double epsilon = 1E-10);
/*!
* \brief Copy constructor
@@ -357,38 +462,7 @@ protected:
*/
virtual QString convertToQString(bool i18n = false) const
{
return this->getUnitName(i18n);
}
/*!
* \brief Conversion factor to SI conversion unit
* \return
*/
double getConversionFactorToSI() const
{
return this->m_conversionFactorToSIConversionUnit;
}
/*!
* Given value to conversion SI conversion unit (e.g. meter, hertz).
* Standard implementaion is simply factor based.
* \param value
* \return
*/
virtual double conversionToSiConversionUnit(double value) const
{
return value * this->m_conversionFactorToSIConversionUnit;
}
/*!
* \brief Value from SI conversion unit to this unit.
* Standard implementation is simply factor based.
* \param value
* \return
*/
virtual double conversionFromSiConversionUnit(double value) const
{
return value / this->m_conversionFactorToSIConversionUnit;
return this->getSymbol(i18n);
}
/*!
@@ -397,7 +471,7 @@ protected:
*/
virtual void marshallToDbus(QDBusArgument &argument) const
{
argument << this->m_unitName;
argument << this->m_symbol;
}
/*!
@@ -411,6 +485,22 @@ protected:
(*this) = CMeasurementUnit::None();
}
/*!
* \brief Unit from symbol
* \param symbol must be a valid unit symbol (without i18n) or empty string (empty means default unit)
* \return
*/
template <class U> static const U &unitFromSymbol(const QString &symbol)
{
if (symbol.isEmpty()) return U::defaultUnit();
const QList<U> &units = U::allUnits();
for (int i = 0; i < units.size(); ++i) {
if (units.at(i).getSymbol() == symbol) return units.at(i);
}
qFatal("Illegal unit name");
return U::defaultUnit(); // just suppress "not all control paths return a value"
}
public:
/*!
* \brief Equal operator ==
@@ -426,33 +516,6 @@ public:
*/
bool operator != (const CMeasurementUnit &other) const;
/*!
* \brief Representing an SI unit? Examples: kilometer, meter, hertz
* \return
*/
bool isSiUnit() const
{
return this->m_isSiUnit;
}
/*!
* \brief Representing an base SI unit? Examples: second, meter
* \return
*/
bool isSiBaseUnit() const
{
return this->m_isSiUnit;
}
/*!
* \brief Representing an SI base unit? Example: meter
* \return
*/
bool isUnprefixedSiUnit() const
{
return this->m_isSiUnit && this->m_multiplier.getFactor() == 1;
}
/*!
* \brief Name such as "meter"
* \param i18n
@@ -460,7 +523,8 @@ public:
*/
QString getName(bool i18n = false) const
{
return i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_name.toStdString().c_str()) : this->m_name;
QString base = i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_name.toStdString().c_str()) : this->m_name;
return this->m_prefix.getName(i18n) + base;
}
/*!
@@ -468,41 +532,19 @@ public:
* \param i18n
* \return
*/
QString getUnitName(bool i18n = false) const
QString getSymbol(bool i18n = false) const
{
return i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_unitName.toStdString().c_str()) : this->m_unitName;
QString base = i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_symbol.toStdString().c_str()) : this->m_symbol;
return this->m_prefix.getSymbol(i18n) + base;
}
/*!
* \brief Type such as "distance", "frequency"
* \return
*/
QString getType() const
{
return this->m_type;
}
/*!
* Given value to conversion SI conversion unit (e.g. meter, hertz).
* Standard implementation is simply factor based.
* \brief Rounded value
* \param value
* \param digits
* \return
*/
double convertToSiConversionUnit(double value) const
{
return (this->m_toSiConverter) ? this->m_toSiConverter((*this), value) : this->conversionToSiConversionUnit(value);
}
/*!
* Value from SI conversion unit to this unit.
* Standard implementation is simply factor based.
* \param value
* \return
*/
double convertFromSiConversionUnit(double value) const
{
return (this->m_fromSiConverter) ? this->m_fromSiConverter((*this), value) : this->conversionFromSiConversionUnit(value);
}
double roundValue(double value, int digits = -1) const;
/*!
* Rounded string utility method, virtual so units can have
@@ -512,15 +554,7 @@ public:
* \param i18n
* \return
*/
virtual QString toQStringRounded(double value, int digits = -1, bool i18n = false) const;
/*!
* \brief Rounded value
* \param value
* \param digits
* \return
*/
double valueRounded(double value, int digits = -1) const;
virtual QString makeRoundedQString(double value, int digits = -1, bool i18n = false) const;
/*!
* \brief Value rounded with unit, e.g. "5.00m", "30kHz"
@@ -529,7 +563,7 @@ public:
* \param i18n
* \return
*/
virtual QString valueRoundedWithUnit(double value, int digits = -1, bool i18n = false) const;
virtual QString makeRoundedQStringWithUnit(double value, int digits = -1, bool i18n = false) const;
/*!
* \brief Threshold for rounding
@@ -544,7 +578,7 @@ public:
* \brief getDisplayDigits
* \return
*/
qint32 getDisplayDigits() const
int getDisplayDigits() const
{
return this->m_displayDigits;
}
@@ -553,26 +587,16 @@ public:
* \brief Multiplier such as "kilo"
* \return
*/
CMeasurementPrefix getMultiplier() const
CMeasurementPrefix getPrefix() const
{
return this->m_multiplier;
return this->m_prefix;
}
/*!
* \brief Factor to convert to given unit
* \param value
* \param to
* \return
* Convert from other unit to this unit.
* \param
*/
double conversionToUnit(double value, const CMeasurementUnit &to) const;
/*!
* Epsilon rounding. In some conversion rouding is required to avoid
* periodical numbers.
* \param value
* \return
*/
double epsilonUpRounding(double value) const;
double convertFrom(double value, const CMeasurementUnit &unit) const;
/*!
* \brief Is given value <= epsilon?
@@ -595,7 +619,7 @@ public:
*/
static CMeasurementUnit &None()
{
static CMeasurementUnit none("none", "", "", false, false, 0.0, CMeasurementPrefix::None(), 0, 0);
static CMeasurementUnit none("none", "", 0.0, 0, 0);
return none;
}
};

View File

@@ -69,6 +69,16 @@ public:
return p;
}
/*!
* \brief Standard pressure datum for flight levels expressed in mmHg, such as in Russia, 760mmHg
* \return
*/
static const CPressure& RuFlightLevelPressure()
{
static CPressure p(760, CPressureUnit::mmHg());
return p;
}
/*!
* \brief Unicom frequency
* \return

View File

@@ -22,7 +22,7 @@ public:
/*!
* \brief Default constructor
*/
CFrequency() : CPhysicalQuantity(0, CFrequencyUnit::Hz(), CFrequencyUnit::Hz()) {}
CFrequency() : CPhysicalQuantity(0, CFrequencyUnit::defaultUnit()) {}
/**
*\brief Copy constructor from base type
@@ -34,7 +34,7 @@ public:
* \param value
* \param unit
*/
CFrequency(double value, const CFrequencyUnit &unit) : CPhysicalQuantity(value, unit, CFrequencyUnit::Hz()) {}
CFrequency(double value, const CFrequencyUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Virtual destructor

View File

@@ -22,7 +22,7 @@ public:
/*!
* \brief Default constructor
*/
CLength() : CPhysicalQuantity(0, CLengthUnit::m(), CLengthUnit::m()) {}
CLength() : CPhysicalQuantity(0, CLengthUnit::defaultUnit()) {}
/**
*\brief Copy constructor from base type
@@ -34,7 +34,7 @@ public:
* \param value
* \param unit
*/
CLength(double value, const CLengthUnit &unit) : CPhysicalQuantity(value, unit, CLengthUnit::m()) {}
CLength(double value, const CLengthUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Virtual destructor

View File

@@ -21,14 +21,14 @@ public:
/*!
* \brief Default constructor
*/
CMass() : CPhysicalQuantity(0, CMassUnit::kg(), CMassUnit::kg()) {}
CMass() : CPhysicalQuantity(0, CMassUnit::defaultUnit()) {}
/*!
* \brief Init by double value
* \param value
* \param unit
*/
CMass(double value, const CMassUnit &unit) : CPhysicalQuantity(value, unit, CMassUnit::kg()) {}
CMass(double value, const CMassUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Copy constructor from base type

View File

@@ -13,25 +13,16 @@ namespace PhysicalQuantities
/*
* Constructor by double
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit) :
m_unit(unit), m_conversionSiUnit(siConversionUnit)
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::CPhysicalQuantity(double value, const MU &unit) :
m_value(value), m_unit(unit)
{
this->setUnitValue(baseValue);
}
/*
* Copy constructor
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::CPhysicalQuantity(const CPhysicalQuantity &other) :
m_unitValueD(other.m_unitValueD), m_convertedSiUnitValueD(other.m_convertedSiUnitValueD),
m_unit(other.m_unit), m_conversionSiUnit(other.m_conversionSiUnit)
{
}
/*
* Destructor
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::~CPhysicalQuantity()
m_value(other.m_value), m_unit(other.m_unit)
{
}
@@ -41,25 +32,8 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::~CPhysicalQuantity()
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator ==(const CPhysicalQuantity<MU, PQ> &other) const
{
if (this == &other) return true;
if (this->m_unit.getType() != other.m_unit.getType()) return false;
// some special cases for best quality
double diff;
const double lenient = 1.001; // even diff already has a rounding issue to be avoided
bool eq = false;
if (this->m_unit == other.m_unit)
{
// same unit, comparison based on double
diff = qAbs(this->m_unitValueD - other.m_unitValueD);
eq = diff <= (lenient * this->m_unit.getEpsilon());
}
else
{
// based on SI value
diff = qAbs(this->m_convertedSiUnitValueD - other.m_convertedSiUnitValueD);
eq = diff <= (lenient * this->m_conversionSiUnit.getEpsilon());
}
return eq;
double diff = abs(this->m_value - other.value(this->m_unit));
return diff <= this->m_unit.getEpsilon();
}
/*
@@ -77,10 +51,8 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ>& CPhysicalQuantity<MU, P
{
if (this == &other) return *this;
this->m_unitValueD = other.m_unitValueD;
this->m_convertedSiUnitValueD = other.m_convertedSiUnitValueD;
this->m_value = other.m_value;
this->m_unit = other.m_unit;
this->m_conversionSiUnit = other.m_conversionSiUnit;
return *this;
}
@@ -89,15 +61,7 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ>& CPhysicalQuantity<MU, P
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator +=(const CPhysicalQuantity<MU, PQ> &other)
{
if (this->m_unit == other.m_unit)
{
this->setUnitValue(other.m_unitValueD + this->m_unitValueD);
}
else
{
double v = other.value(this->m_unit);
this->setUnitValue(v + this->m_unitValueD);
}
this->m_value += other.value(this->m_unit);
return *this;
}
@@ -114,17 +78,17 @@ template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator +(const PQ
/*
* Explicit plus
*/
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::addUnitValue(double value)
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::addValueSameUnit(double value)
{
this->setUnitValue(this->m_unitValueD + value);
this->m_value += value;
}
/*
* Explicit minus
*/
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::substractUnitValue(double value)
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::substractValueSameUnit(double value)
{
this->setUnitValue(this->m_unitValueD - value);
this->m_value -= value;
}
/*
@@ -132,15 +96,7 @@ template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::substractUnitValue
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator -=(const CPhysicalQuantity<MU, PQ> &other)
{
if (this->m_unit == other.m_unit)
{
this->setUnitValue(other.m_unitValueD - this->m_unitValueD);
}
else
{
double v = other.value(this->m_unit);
this->setUnitValue(v - this->m_unitValueD);
}
this->m_value -= other.value(this->m_unit);
return *this;
}
@@ -157,38 +113,38 @@ template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator -(const PQ
/*
* Multiply operator
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator *=(double multiply)
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator *=(double factor)
{
this->setUnitValue(this->m_unitValueD * multiply);
this->m_value *= factor;
return *this;
}
/*
* Multiply operator
*/
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator *(double multiply) const
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator *(double factor) const
{
PQ copy = *derived();
copy *= multiply;
copy *= factor;
return copy;
}
/*
* Divide operator /=
*/
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator /=(double divide)
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator /=(double divisor)
{
this->setUnitValue(this->m_unitValueD / divide);
this->m_value /= divisor;
return *this;
}
/*
* Divide operator /
*/
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator /(double divide) const
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator /(double divisor) const
{
PQ copy = *derived();
copy /= divide;
copy /= divisor;
return copy;
}
@@ -199,9 +155,7 @@ template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator <(const C
{
if ((*this) == other) return false;
// == considers epsilon, so we now have a diff > epsilon here
double diff = this->m_convertedSiUnitValueD - other.m_convertedSiUnitValueD;
return (diff < 0);
return (this->m_value < other.value(this->m_unit));
}
/*
@@ -238,9 +192,8 @@ template <class MU, class PQ> PQ &CPhysicalQuantity<MU, PQ>::switchUnit(const MU
{
if (this->m_unit != newUnit)
{
double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit);
this->m_value = newUnit.convertFrom(this->m_value, this->m_unit);
this->m_unit = newUnit;
this->setUnitValue(cf);
}
return *derived();
}
@@ -248,60 +201,9 @@ template <class MU, class PQ> PQ &CPhysicalQuantity<MU, PQ>::switchUnit(const MU
/*
* Init by double
*/
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::setUnitValue(double baseValue)
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::setValueSameUnit(double baseValue)
{
this->m_unitValueD = baseValue;
this->setConversionSiUnitValue();
}
/*
* Set SI value
*/
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::setConversionSiUnitValue()
{
double si = this->m_unit.convertToSiConversionUnit(this->m_unitValueD);
this->m_convertedSiUnitValueD = si;
}
/*
* Round
*/
template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::unitValueToDoubleRounded(int digits) const
{
return this->m_unit.valueRounded(this->m_unitValueD, digits);
}
/*
* Rounded value to QString
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::unitValueToQStringRounded(int digits) const
{
return this->m_unit.toQStringRounded(this->m_unitValueD, digits);
}
/*
* Rounded with unit
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::unitValueRoundedWithUnit(int digits, bool i18n) const
{
return this->m_unit.valueRoundedWithUnit(this->m_unitValueD, digits, i18n);
}
/*
* Rounded SI value to QString
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::convertedSiValueToQStringRounded(int digits) const
{
if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits();
return this->m_conversionSiUnit.toQStringRounded(this->m_convertedSiUnitValueD, digits);
}
/*
* SI base unit value with unit
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::convertedSiValueRoundedWithUnit(int digits, bool i18n) const
{
return this->m_conversionSiUnit.valueRoundedWithUnit(this->m_convertedSiUnitValueD, digits, i18n);
this->m_value = baseValue;
}
/*
@@ -309,9 +211,7 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::convertedSiValu
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::valueRoundedWithUnit(const MU &unit, int digits, bool i18n) const
{
if (unit == this->m_unit) return this->unitValueRoundedWithUnit(digits, i18n);
if (unit == this->m_conversionSiUnit) return this->convertedSiValueRoundedWithUnit(digits, i18n);
return unit.valueRoundedWithUnit(this->value(unit), digits, i18n);
return unit.makeRoundedQStringWithUnit(this->value(unit), digits, i18n);
}
/*
@@ -319,7 +219,7 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU, PQ>::valueRoundedWit
*/
template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::valueRounded(const MU &unit, int digits) const
{
return unit.valueRounded(this->value(unit), digits);
return unit.roundValue(this->value(unit), digits);
}
/*
@@ -327,19 +227,7 @@ template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::valueRounded(con
*/
template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::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 = unit.convertFromSiConversionUnit(this->m_convertedSiUnitValueD);
return v;
}
/*
* Round utility method
*/
template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::convertedSiValueToDoubleRounded(int digits) const
{
if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits();
return this->m_conversionSiUnit.valueRounded(this->m_convertedSiUnitValueD, digits);
return unit.convertFrom(this->m_value, this->m_unit);
}
// see here for the reason of thess forward instantiations

View File

@@ -27,8 +27,13 @@ namespace PhysicalQuantities
template <class MU, class PQ> class CPhysicalQuantity : public BlackMisc::CBaseStreamStringifier
{
private:
double m_unitValueD; //!< value backed by double
double m_convertedSiUnitValueD; //!< SI unit value
double m_value; //!< numeric part
MU m_unit; //!< unit part
/*!
* Which subclass of CMeasurementUnit does this quantity use?
*/
typedef MU UnitClass;
/*!
* \brief Easy access to derived class (CRTP template parameter)
@@ -49,16 +54,25 @@ private:
}
protected:
MU m_unit; //!< unit
MU m_conversionSiUnit; //!< corresponding SI base unit
/*!
* \brief Constructor with double
* \param baseValue
* \param value
* \param unit
* \param siConversionUnit
*/
CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit);
CPhysicalQuantity(double value, const MU &unit);
/*!
* \brief Copy constructor
* \param other
*/
CPhysicalQuantity(const CPhysicalQuantity &other);
/*!
* \brief Assignment operator =
* \param other
* \return
*/
CPhysicalQuantity &operator =(const CPhysicalQuantity &other);
/*!
* \brief Name as string
@@ -67,32 +81,20 @@ protected:
*/
virtual QString convertToQString(bool i18n = false) const
{
return this->unitValueRoundedWithUnit(-1, i18n);
return this->valueRoundedWithUnit(this->getUnit(), -1, i18n);
}
/*!
* \brief Init by double
* \param baseValue
* \brief Change value without changing unit
* \param value
*/
void setUnitValue(double baseValue);
/*!
* \brief Set the SI value
*/
void setConversionSiUnitValue();
void setValueSameUnit(double value);
public:
/*!
* \brief Copy constructor
* \param other
*/
CPhysicalQuantity(const CPhysicalQuantity &other);
/*!
* \brief Virtual destructor
*/
virtual ~CPhysicalQuantity();
virtual ~CPhysicalQuantity() {}
/*!
* \brief Unit of the distance
@@ -104,48 +106,12 @@ public:
}
/*!
* \brief Conversion SI unit
* \return
*/
MU getConversionSiUnit() const
{
return this->m_conversionSiUnit;
}
/*!
* \brief Switch unit, e.g. feet to meter
* \brief Change unit, and convert value to maintain the same quantity
* \param newUnit
* \return
*/
PQ &switchUnit(const MU &newUnit);
/*!
* \brief Value in SI base unit? Meter is an SI base unit, hertz not!
* \return
*/
bool isSiBaseUnit() const
{
return this->m_unit.isSiBaseUnit();
}
/*!
* \brief Value in SI unit? Hertz is an derived SI unit, NM not!
* \return
*/
bool isSiUnit() const
{
return this->m_unit.isSiUnit();
}
/*!
* \brief Value in unprefixed SI unit? Meter is a unprefixed, kilometer a prefixed SI Unit
* \return
*/
bool isUnprefixedSiUnit() const
{
return this->m_unit.isUnprefixedSiUnit();
}
/*!
* \brief Value in given unit
* \param unit
@@ -154,7 +120,16 @@ public:
double value(const MU &unit) const;
/*!
* \brief Rounded value in unit
* \brief Value in current unit
* \return
*/
double value() const
{
return this->m_value;
}
/*!
* \brief Rounded value in given unit
* \param unit
* \param digits
* \return
@@ -162,7 +137,17 @@ public:
double valueRounded(const MU &unit, int digits = -1) const;
/*!
* \brief Value to QString with unit, e.g. "5.00m"
* \brief Rounded value in current unit
* \param digits
* \return
*/
double valueRounded(int digits = -1) const
{
return this->valueRounded(this->m_unit, digits);
}
/*!
* \brief Value to QString with the given unit, e.g. "5.00m"
* \param unit
* \param digits
* \param i18n
@@ -171,80 +156,27 @@ public:
QString valueRoundedWithUnit(const MU &unit, int digits = -1, bool i18n = false) const;
/*!
* \brief Value as double
* \return
*/
double unitValueToDouble() const
{
return this->m_unitValueD;
}
/*!
* \brief Value to QString with unit, e.g. "5.00m"
* \brief Value to QString with the current unit, e.g. "5.00m"
* \param digits
* \param i18n
* \return
*/
QString unitValueRoundedWithUnit(int digits = -1, bool i18n = false) const;
/*!
* \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 Conversion SI value as double
* \return
*/
double convertedSiValueToDouble() const
QString valueRoundedWithUnit(int digits = -1, bool i18n = false) const
{
return this->m_convertedSiUnitValueD;
return this->valueRoundedWithUnit(this->m_unit, digits, i18n);
}
/*!
* \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
* \param i18n
* \return
*/
QString convertedSiValueRoundedWithUnit(int digits = -1, bool i18n = false) const;
/*!
* \brief Add to the unit value.
* \remarks Since overloading the + operator with double did lead to unintended conversions, as explicit method
* \brief Add to the value in the current unit.
* \param value
*/
void addUnitValue(double value);
void addValueSameUnit(double value);
/*!
* \brief Substract to the unit value.
* \remarks Since overloading the - operator with double did lead to unintended conversions, as explicit method
* \brief Substract from the value in the current unit.
* \param value
*/
void substractUnitValue(double value);
void substractValueSameUnit(double value);
/*!
* \brief Multiply operator *=
@@ -341,13 +273,6 @@ public:
*/
bool operator >=(const CPhysicalQuantity &other) const;
/*!
* \brief Assignment operator =
* \param other
* \return
*/
CPhysicalQuantity &operator =(const CPhysicalQuantity &other);
/*!
* \brief Plus operator +
* \param other
@@ -368,25 +293,25 @@ public:
*/
bool isZeroEpsilon() const
{
return this->m_unit.isEpsilon(this->m_unitValueD);
return this->m_unit.isEpsilon(this->m_value);
}
/*!
* \brief Value >= 0 epsilon considered
* \return
*/
bool isGreaterOrEqualZeroEpsilon() const
bool isNonNegativeEpsilon() const
{
return this->isZeroEpsilon() || this->m_unitValueD > 0;
return this->isZeroEpsilon() || this->m_value > 0;
}
/*!
* \brief Value <= 0 epsilon considered
* \return
*/
bool isLessOrEqualZeroEpsilon() const
bool isNonPositiveEpsilon() const
{
return this->isZeroEpsilon() || this->m_unitValueD < 0;
return this->isZeroEpsilon() || this->m_value < 0;
}
/*!
@@ -395,10 +320,9 @@ public:
*/
virtual void marshallToDbus(QDBusArgument &argument) const
{
argument << this->m_unitValueD;
argument << this->m_convertedSiUnitValueD;
argument << this->value(UnitClass::defaultUnit());
argument << this->m_value;
argument << this->m_unit;
argument << this->m_conversionSiUnit;
}
/*!
@@ -407,10 +331,10 @@ public:
*/
virtual void unmarshallFromDbus(const QDBusArgument &argument)
{
argument >> this->m_unitValueD;
argument >> this->m_convertedSiUnitValueD;
double ignore;
argument >> ignore;
argument >> this->m_value;
argument >> this->m_unit;
argument >> this->m_conversionSiUnit;
}
/*!

View File

@@ -23,7 +23,7 @@ public:
/*!
* \brief Default constructor
*/
CPressure() : CPhysicalQuantity(0, CPressureUnit::Pa(), CPressureUnit::Pa()) {}
CPressure() : CPhysicalQuantity(0, CPressureUnit::defaultUnit()) {}
/**
*\brief Copy constructor from base type
@@ -35,7 +35,7 @@ public:
* \param value
* \param unit
*/
CPressure(double value, const CPressureUnit &unit) : CPhysicalQuantity(value, unit, CPressureUnit::Pa()) {}
CPressure(double value, const CPressureUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Virtual destructor

View File

@@ -23,7 +23,7 @@ public:
/*!
* \brief Default constructor
*/
CSpeed() : CPhysicalQuantity(0, CSpeedUnit::m_s(), CSpeedUnit::m_s()) {}
CSpeed() : CPhysicalQuantity(0, CSpeedUnit::defaultUnit()) {}
/*!
*\brief Copy constructor from base type
@@ -35,7 +35,7 @@ public:
* \param value
* \param unit
*/
CSpeed(double value, const CSpeedUnit &unit) : CPhysicalQuantity(value, unit, CSpeedUnit::m_s()) {}
CSpeed(double value, const CSpeedUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Destructor

View File

@@ -22,7 +22,7 @@ public:
/*!
* \brief Default constructor
*/
CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::K(), CTemperatureUnit::K()) {}
CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::defaultUnit()) {}
/**
* \brief Copy constructor from base type
@@ -34,7 +34,7 @@ public:
* \param value
* \param unit
*/
CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K()) {}
CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit) {}
/*!
* \brief Destructor

View File

@@ -23,7 +23,7 @@ public:
/*!
* \brief Default constructor
*/
CTime() : CPhysicalQuantity(0, CTimeUnit::s(), CTimeUnit::s()) {}
CTime() : CPhysicalQuantity(0, CTimeUnit::defaultUnit()) {}
/**
*\brief Copy constructor from base type
@@ -35,7 +35,7 @@ public:
* \param value
* \param unit
*/
CTime(double value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit, CTimeUnit::s()) {}
CTime(double value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit) {}
/*!
* \brief Destructor

View File

@@ -10,79 +10,74 @@ namespace BlackMisc
namespace PhysicalQuantities
{
/*
* Convert to SI
*/
double CTemperatureUnit::conversionToSiConversionUnit(double value) const
{
double v = value + this->m_conversionOffsetToSi;
v *= this->getConversionFactorToSI();
return v;
}
using BlackMisc::Math::CMath;
/*
* Convert from SI
* Rounded to QString
*/
double CTemperatureUnit::conversionFromSiConversionUnit(double value) const
QString CAngleUnit::makeRoundedQString(double value, int digits, bool i18n) const
{
double v = value / this->getConversionFactorToSI();
v -= this->m_conversionOffsetToSi;
return v;
}
/*
* Convert from SI
*/
double CAngleUnit::conversionSexagesimalFromSi(const CMeasurementUnit &angleUnit, double value)
{
// using rounding here, since fractions can lead to ugly sexagesimal conversion
// e.g. 185.499999 gives 185 29' 59.9999"
value = angleUnit.epsilonUpRounding(value * 180 / M_PI); // degree
double 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));
return v;
}
/*
* Convert to SI
*/
double CAngleUnit::conversionSexagesimalToSi(const CMeasurementUnit &, double value)
{
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;
if (digits < 0) digits = this->getDisplayDigits();
QString s;
if ((*this) == CAngleUnit::sexagesimalDeg())
{
double de = CMath::trunc(value);
double mi = CMath::trunc((value - de) * 100.0);
double se = CMath::trunc((value - de - mi / 100.0) * 1000000) / 100.0;
const char *fmt = value < 0 ? "-%L1 %L2'%L3\"" : "%L1 %L2'%L3\"";
s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt;
s = s.arg(fabs(de), 0, 'f', 0).arg(fabs(mi), 2, 'f', 0, '0').arg(fabs(se), 2, 'f', digits, '0');
}
else if ((*this) == CAngleUnit::sexagesimalDegMin())
{
double de = CMath::trunc(value);
double mi = CMath::trunc((value - de) * 100.0);
const char *fmt = value < 0 ? "-%L1 %L2'" : "%L1 %L2'";
s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt;
s = s.arg(fabs(de), 0, 'f', 0).arg(fabs(mi), 2, 'f', digits, '0');
}
else
{
s = this->CMeasurementUnit::makeRoundedQString(value, digits, i18n);
}
return s;
}
/*
* Rounded to QString
*/
QString CAngleUnit::toQStringRounded(double value, int digits, bool i18n) const
QString CTimeUnit::makeRoundedQString(double value, int digits, bool i18n) const
{
if (digits < 0) digits = this->getDisplayDigits();
QString s;
if ((*this) == CAngleUnit::sexagesimalDeg())
if ((*this) == CTimeUnit::hms())
{
// special formatting for sexagesimal degrees
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);
s = s.append(i18n ? CAngleUnit::deg().getUnitName(true) : " ");
s = s.append(QString::number(mi)).append("'").append(ses).append("\"");
double hr = CMath::trunc(value);
double mi = CMath::trunc((value - hr) * 100.0);
double se = CMath::trunc((value - hr - mi / 100.0) * 1000000) / 100.0;
const char *fmt = value < 0 ? "-%L1h%L2m%L3s" : "%L1h%L2m%L3s";
s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt;
s = s.arg(fabs(hr), 0, 'f', 0).arg(fabs(mi), 2, 'f', 0, '0').arg(fabs(se), 2, 'f', digits, '0');
}
else if ((*this) == CTimeUnit::hrmin())
{
double hr = CMath::trunc(value);
double mi = CMath::trunc((value - hr) * 100.0);
const char *fmt = value < 0 ? "-%L1h%L2m" : "%L1h%L2m";
s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt;
s = s.arg(fabs(hr), 0, 'f', 0).arg(fabs(mi), 2, 'f', digits, '0');
}
else if ((*this) == CTimeUnit::minsec())
{
double mi = CMath::trunc(value);
double se = CMath::trunc((value - mi) * 100.0);
const char *fmt = value < 0 ? "-%L2m%L3s" : "%L2m%L3s";
s = i18n ? QCoreApplication::translate("CMeasurementUnit", fmt) : fmt;
s = s.arg(fabs(mi), 0, 'f', 0).arg(fabs(se), 2, 'f', digits, '0');
}
else
{
s = this->CMeasurementUnit::toQStringRounded(value, digits);
s = this->CMeasurementUnit::makeRoundedQString(value, digits, i18n);
}
return s;
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,11 +37,11 @@ void CTestAviation::headingBasics()
QVERIFY2(h4 == h1, "Values shall be equal");
h1 -= h1;
QVERIFY2(h1.unitValueToDouble() == 0, "Value shall be 0");
QVERIFY2(h1.value() == 0, "Value shall be 0");
// h4 = h1 + h2; does not work, because misleading
h2 += h2; // add just angle
QVERIFY2(h2.unitValueToDouble() == 360, "Value shall be 360");
QVERIFY2(h2.value() == 360, "Value shall be 360");
}
/*

View File

@@ -14,7 +14,7 @@ void CTestGeo::geoBasics()
CLatitude lati(10, CAngleUnit::deg());
QVERIFY2(lati * 2 == lati + lati, "Latitude addition should be equal");
lati += CLatitude(20, CAngleUnit::deg());
QVERIFY2(lati.unitValueToDoubleRounded() == 30.0, "Latitude should be 30 degrees");
QVERIFY2(lati.valueRounded() == 30.0, "Latitude should be 30 degrees");
double lat = 27.999999, lon = 86.999999, h = 8820.999999; // Mt Everest
CCoordinateGeodetic startGeoVec(lat, lon, h);

View File

@@ -15,8 +15,6 @@ namespace BlackMiscTest
*/
void CTestPhysicalQuantities::unitsBasics()
{
QVERIFY2(CMeasurementPrefix::k() > CMeasurementPrefix::h(), "kilo > hecto");
// some tests on units
CLengthUnit du1 = CLengthUnit::m(); // Copy
CLengthUnit du2 = CLengthUnit::m(); // Copy
@@ -25,7 +23,6 @@ void CTestPhysicalQuantities::unitsBasics()
du2 = CLengthUnit::m(); // Copy
QVERIFY2(du1 == du2, "Compare by value 2");
QVERIFY2(CLengthUnit::m() == CLengthUnit::m(), "Compare by value");
QVERIFY2(CMeasurementPrefix::h() < CMeasurementPrefix::M(), "hecto < mega");
CFrequencyUnit fu1 = CFrequencyUnit::Hz();
QVERIFY2(fu1 != du1, "Hz must not be meter");
@@ -54,12 +51,12 @@ void CTestPhysicalQuantities::lengthBasics()
// epsilon tests
d1 = d2; // both in same unit
d1.addUnitValue(d1.getUnit().getEpsilon()); // this should be still the same
d1.addValueSameUnit(d1.getUnit().getEpsilon() / 2.0); // this should be still the same
QVERIFY2(d1 == d2, "Epsilon: 100cm + epsilon shall be 100cm");
QVERIFY2(!(d1 != d2), "Epsilon: 100cm + epsilon shall be still 100cm");
QVERIFY2(!(d1 > d2), "d1 shall not be greater");
d1.addUnitValue(d1.getUnit().getEpsilon()); // now over epsilon threshold
d1.addValueSameUnit(d1.getUnit().getEpsilon()); // now over epsilon threshold
QVERIFY2(d1 != d2, "Epsilon exceeded: 100 cm + 2 epsilon shall not be 100cm");
QVERIFY2(d1 > d2, "d1 shall be greater");
}
@@ -82,8 +79,8 @@ void CTestPhysicalQuantities::frequencyTests()
{
CFrequency f1(1, CFrequencyUnit::MHz());
QVERIFY2(f1.valueRounded(CFrequencyUnit::kHz(), 2) == 1000, "Mega is 1000kHz");
QVERIFY2(f1.unitValueToDouble() == 1 , "1MHz");
QVERIFY2(f1.convertedSiValueToDouble() == 1000000 , "1E6 Hz");
QVERIFY2(f1.value() == 1 , "1MHz");
QVERIFY2(f1.value(CFrequencyUnit::defaultUnit()) == 1000000 , "1E6 Hz");
CFrequency f2(CMeasurementPrefix::M().toDouble(), CFrequencyUnit::Hz()) ; // 1 Megahertz
QVERIFY2(f1 == f2 , "MHz is 1E6 Hz");
}
@@ -96,9 +93,13 @@ void CTestPhysicalQuantities::angleTests()
CAngle a1(180, CAngleUnit::deg());
CAngle a2(1.5 * CAngle::PI(), CAngleUnit::rad());
CAngle a3(35.4336, CAngleUnit::sexagesimalDeg()); // 35.72666
CAngle a4(35.436, CAngleUnit::sexagesimalDegMin()); // 35.72666
CAngle a5(-60.3015, CAngleUnit::sexagesimalDeg()); // negative angles = west longitude or south latitude
a2.switchUnit(CAngleUnit::deg());
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");
QVERIFY2(a4.valueRounded(CAngleUnit::deg()) == 35.73, "Expecting 35.73");
QVERIFY2(a5.valueRounded(CAngleUnit::deg(), 4) == -60.5042, "Expecting -60.5042");
}
/*
@@ -107,11 +108,11 @@ void CTestPhysicalQuantities::angleTests()
void CTestPhysicalQuantities::massTests()
{
CMass w1(1000, CMassUnit::kg());
CMass w2(w1.unitValueToDouble(), CMassUnit::kg());
CMass w2(w1.value(), CMassUnit::kg());
w2.switchUnit(CMassUnit::t());
QVERIFY2(w2.unitValueToDouble() == 1, "1tonne shall be 1000kg");
QVERIFY2(w2.value() == 1, "1tonne shall be 1000kg");
w2.switchUnit(CMassUnit::lb());
QVERIFY2(w2.unitValueToDoubleRounded(2) == 2204.62, "1tonne shall be 2204pounds");
QVERIFY2(w2.valueRounded(2) == 2204.62, "1tonne shall be 2204pounds");
QVERIFY2(w1 == w2, "Masses shall be equal");
}
@@ -127,7 +128,7 @@ void CTestPhysicalQuantities::pressureTests()
// does not match exactly
QVERIFY2(p1 != p2, "Standard pressure test little difference");
QVERIFY2(p1.unitValueToDouble() == p4.unitValueToDouble(), "mbar/hPa test");
QVERIFY2(p1.value() == p4.value(), "mbar/hPa test");
}
/*
@@ -139,19 +140,25 @@ void CTestPhysicalQuantities::temperatureTests()
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(t1.valueRounded(CTemperatureUnit::K()) == 273.15, qPrintable(QString("0C shall be 273.15K, not %1 K").arg(t1.valueRounded(CTemperatureUnit::K()))));
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()))));
}
/*
* Temperature tests
* Time tests
*/
void CTestPhysicalQuantities::timeTests()
{
CTime t1(1, CTimeUnit::h());
QVERIFY2(t1.convertedSiValueToDouble() == 3600, "1hour shall be 3600s");
CTime t2(1.5, CTimeUnit::h());
CTime t3(1.25, CTimeUnit::min());
CTime t4(1.0101, CTimeUnit::hms());
QVERIFY2(t1.value(CTimeUnit::defaultUnit()) == 3600, "1hour shall be 3600s");
QVERIFY2(t2.value(CTimeUnit::hrmin()) == 1.30, "1.5hour shall be 1h30m");
QVERIFY2(t3.value(CTimeUnit::minsec()) == 1.15, "1.25min shall be 1m15s");
QVERIFY2(t4.value(CTimeUnit::s()) == 3661, "1h01m01s shall be 3661s");
}
/*
@@ -160,13 +167,13 @@ void CTestPhysicalQuantities::timeTests()
void CTestPhysicalQuantities::accelerationTests()
{
CLength oneMeter(1, CLengthUnit::m());
double ftFactor = oneMeter.switchUnit(CLengthUnit::ft()).unitValueToDouble();
double ftFactor = oneMeter.switchUnit(CLengthUnit::ft()).value();
CAcceleration a1(10.0, CAccelerationUnit::m_s2());
CAcceleration a2(a1);
a1.switchUnit(CAccelerationUnit::ft_s2());
QVERIFY2(a1 == a2, "Accelerations should be similar");
QVERIFY2(BlackMisc::Math::CMath::round(a1.unitValueToDouble() * ftFactor, 6) == a2.unitValueToDoubleRounded(6),
QVERIFY2(BlackMisc::Math::CMath::round(a1.value() * ftFactor, 6) == a2.valueRounded(6),
"Numerical values should be equal");
}
@@ -177,13 +184,13 @@ void CTestPhysicalQuantities::memoryTests()
{
CLength *c = new CLength(100, CLengthUnit::m());
c->switchUnit(CLengthUnit::NM());
QVERIFY2(c->getUnit() == CLengthUnit::NM() && c->getConversionSiUnit() == CLengthUnit::m(),
QVERIFY2(c->getUnit() == CLengthUnit::NM() && CLengthUnit::defaultUnit() == CLengthUnit::m(),
"Testing distance units failed");
delete c;
CAngle *a = new CAngle(100, CAngleUnit::rad());
a->switchUnit(CAngleUnit::deg());
QVERIFY2(a->getUnit() == CAngleUnit::deg() && c->getConversionSiUnit() == CAngleUnit::rad(),
QVERIFY2(a->getUnit() == CAngleUnit::deg() && CAngleUnit::defaultUnit() == CAngleUnit::deg(),
"Testing angle units failed");
delete a;
}
@@ -201,7 +208,7 @@ void CTestPhysicalQuantities::basicArithmetic()
p3 /= 2.0;
QVERIFY2(p3 == p1, "Pressure needs to be the same (1time)");
p3 = p3 - p3;
QVERIFY2(p3.unitValueToDouble() == 0, "Value needs to be zero");
QVERIFY2(p3.value() == 0, "Value needs to be zero");
p3 = CPressure(1013, CPressureUnit::hPa());
QVERIFY2(p3 * 1.5 == 1.5 * p3, "Basic commutative test on PQ failed");
}