CAngleUnit::sexagesimalDeg(), moved conversion to virtual method in CMeasurmenetUnit, made string conversion virtual and also moved it to CMeasurmenetUnit (=>individual formatters). Time unit added.

This commit is contained in:
Klaus Basan
2013-03-31 00:35:25 +01:00
parent be34b78425
commit f77258343d
17 changed files with 542 additions and 299 deletions

View File

@@ -19,24 +19,25 @@ int main(int argc, char *argv[])
// cases which must not work
// CMeasurementUnit mu; //must not work
// CLengthUnit du1(CAngleUnit::rad());
CLengthUnit du2(CLengthUnit::cm());
CLengthUnit du3(CLengthUnit::ft());
const CLength d1(5.0, CLengthUnit::ft()); // 5 ft
CLength d2(1, CLengthUnit::NM()); // 1NM
CLength d3(1, CLengthUnit::km());
CLength d4(d3);
CLengthUnit lu1(CLengthUnit::cm());
CLengthUnit lu2(CLengthUnit::ft());
qDebug() << lu1 << lu2;
const CLength l1(5.0, CLengthUnit::ft()); // 5 ft
CLength l2(1, CLengthUnit::NM()); // 1NM
CLength l3(1, CLengthUnit::km());
CLength l4(l3);
qDebug() << CLengthUnit::ft();
qDebug() << d1 << d2 << d3 << d4;
qDebug() << d1.valueRoundedWithUnit(CLengthUnit::ft(),5)
<< d2.valueRoundedWithUnit(CLengthUnit::km());
qDebug() << d3.getUnit();
qDebug() << l1 << l2 << l3 << l4;
qDebug() << l1.valueRoundedWithUnit(CLengthUnit::ft(),5)
<< l2.valueRoundedWithUnit(CLengthUnit::km());
qDebug() << l3.getUnit();
d2.switchUnit(CLengthUnit::ft()); // now in ft
d3 += d3; // 2km now
d3 *= 1.5;// 3km now
qDebug() << d2 << d3;
l2.switchUnit(CLengthUnit::ft()); // now in ft
l3 += l3; // 2km now
l3 *= 1.5;// 3km now
qDebug() << l2 << l3;
CFrequency f1(1E6, CFrequencyUnit::Hz()); // 1MHz
qDebug() << f1 << f1.valueRoundedWithUnit(CFrequencyUnit::MHz()) << f1.valueRoundedWithUnit(CFrequencyUnit::GHz(), 3);
@@ -50,6 +51,8 @@ int main(int argc, char *argv[])
CAngle a1(180, CAngleUnit::deg());
CAngle a2(1.5 * CAngle::pi(), CAngleUnit::rad());
CAngle a3(180.5, CAngleUnit::deg());
CAngle a4(35.4336,CAngleUnit::sexagesimalDeg()); // 35.72666
a1 += a2;
// a1 = d2; // must not work
qDebug() << a1;
@@ -60,6 +63,9 @@ int main(int argc, char *argv[])
a2.switchUnit(CAngleUnit::deg());
qDebug() << a1.unitValueRoundedWithUnit() << a1.piFactor();
qDebug() << a2;
a3.switchUnit(CAngleUnit::sexagesimalDeg());
a4.switchUnit(CAngleUnit::deg());
qDebug() << a3 << a4;
CMass w1(1,CMassUnit::t());
CMass w2(w1);
@@ -88,6 +94,11 @@ int main(int argc, char *argv[])
CLengthUnit duB(CLengthUnit::cm());
qDebug() << duB;
CTime ti1(1, CTimeUnit::h());
CTime ti2(ti1);
ti2.switchUnit(CTimeUnit::ms());
qDebug() << ti1 << ti2;
// bye
return a.exec();
}

View File

@@ -20,7 +20,10 @@ public:
*/
CAviationVerticalPosition();
/*!
* \brief Default constructor
* \brief Constructor
* \param height
* \param elevation
* \param altitude
*/
CAviationVerticalPosition(const CLength &height, const CLength &elevation, const CLength &altitude);
/*!
@@ -34,6 +37,18 @@ public:
* \return
*/
static CAviationVerticalPosition getHeight(const CLength &initValue) { return CAviationVerticalPosition(initValue, CAviationVerticalPosition::valueNotSet(), CAviationVerticalPosition::valueNotSet());}
/*!
* \brief Factory method for convenience if only one component is available
* \param initValue
* \return
*/
static CAviationVerticalPosition getElevation(const CLength &initValue) { return CAviationVerticalPosition(CAviationVerticalPosition::valueNotSet(), initValue, CAviationVerticalPosition::valueNotSet());}
/*!
* \brief Factory method for convenience if only one component is available
* \param initValue
* \return
*/
static CAviationVerticalPosition getAltitude(const CLength &initValue) { return CAviationVerticalPosition(CAviationVerticalPosition::valueNotSet(), CAviationVerticalPosition::valueNotSet(), initValue);}
};
} // namespace

View File

@@ -48,7 +48,8 @@ HEADERS += \
avverticalposition.h \
pqunits.h \
pqallquantities.h \
pqlength.h
pqlength.h \
pqtime.h
SOURCES += \
logmessage.cpp \
@@ -71,7 +72,7 @@ SOURCES += \
message_system.cpp \
pqphysicalquantity.cpp \
pqbase.cpp \
pqtemperature.cpp \
pqunits.cpp \
avverticalposition.cpp
DESTDIR = ../../lib

View File

@@ -13,6 +13,6 @@
#include "blackmisc/pqspeed.h"
#include "blackmisc/pqtemperature.h"
#include "blackmisc/pqangle.h"
#include "blackmisc/pqtime.h"
#endif // PQUNITSALL_H

View File

@@ -45,7 +45,7 @@ public:
* \brief Value as factor of PI (e.g.0.5PI)
* \return
*/
double piFactor() const { return CPhysicalQuantity::round(this->convertedSiValueToDouble() / M_PI,6);}
double piFactor() const { return CMeasurementUnit::round(this->convertedSiValueToDouble() / M_PI,6);}
};
} // namespace

View File

@@ -10,7 +10,7 @@ namespace BlackMisc {
* Constructor
*/
CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitName, double factor):
_name(name),_prefix(unitName),_factor(factor)
m_name(name),m_prefix(unitName),m_factor(factor)
{
// void
}
@@ -19,7 +19,7 @@ CMeasurementPrefix::CMeasurementPrefix(const QString &name, const QString &unitN
* Constructor
*/
CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier) :
_name(otherMultiplier._name), _prefix(otherMultiplier._prefix), _factor(otherMultiplier._factor)
m_name(otherMultiplier.m_name), m_prefix(otherMultiplier.m_prefix), m_factor(otherMultiplier.m_factor)
{
// void
}
@@ -30,9 +30,9 @@ CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier
CMeasurementPrefix& CMeasurementPrefix::operator=(const CMeasurementPrefix &otherMultiplier) {
if (this == &otherMultiplier) return *this; // Same object? Yes, so skip assignment, and just return *this
this->_name = otherMultiplier._name;
this->_prefix=otherMultiplier._prefix;
this->_factor=otherMultiplier._factor;
this->m_name = otherMultiplier.m_name;
this->m_prefix=otherMultiplier.m_prefix;
this->m_factor=otherMultiplier.m_factor;
return *this;
}
@@ -42,7 +42,7 @@ CMeasurementPrefix& CMeasurementPrefix::operator=(const CMeasurementPrefix &othe
bool CMeasurementPrefix::operator ==(const CMeasurementPrefix &otherMultiplier) const
{
if ( this == &otherMultiplier ) return true;
return this->_factor == otherMultiplier._factor && this->_name == otherMultiplier._name;
return this->m_factor == otherMultiplier.m_factor && this->m_name == otherMultiplier.m_name;
}
/**
@@ -58,7 +58,7 @@ bool CMeasurementPrefix::operator !=(const CMeasurementPrefix &otherMultiplier)
*/
bool CMeasurementPrefix::operator >(const CMeasurementPrefix &otherMultiplier) const
{
return this->_factor > otherMultiplier._factor;
return this->m_factor > otherMultiplier.m_factor;
}
/**
@@ -66,7 +66,7 @@ bool CMeasurementPrefix::operator >(const CMeasurementPrefix &otherMultiplier) c
*/
bool CMeasurementPrefix::operator <(const CMeasurementPrefix &otherMultiplier) const
{
return this->_factor < otherMultiplier._factor;
return this->m_factor < otherMultiplier.m_factor;
}
/**
@@ -74,7 +74,7 @@ bool CMeasurementPrefix::operator <(const CMeasurementPrefix &otherMultiplier) c
*/
QDebug operator<<(QDebug d, const CMeasurementPrefix &multiplier)
{
d << multiplier._name;
d << multiplier.m_name;
return d;
}
@@ -83,7 +83,7 @@ QDebug operator<<(QDebug d, const CMeasurementPrefix &multiplier)
*/
CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier)
{
log << multiplier._name;
log << multiplier.m_name;
return log;
}
@@ -95,8 +95,8 @@ CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier)
* Constructor
*/
CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &unitName, const QString &type, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI, const CMeasurementPrefix &multiplier, qint32 displayDigits, double epsilon):
_name(name), _unitName(unitName), _type(type), _isSIUnit(isSIUnit), _isSIBaseUnit(isSIBaseUnit),_displayDigits(displayDigits),_conversionFactorToSIConversionUnit(conversionFactorToSI),
_epsilon(epsilon), _multiplier(multiplier)
m_name(name), m_unitName(unitName), m_type(type), m_isSIUnit(isSIUnit), m_isSIBaseUnit(isSIBaseUnit),m_displayDigits(displayDigits),m_conversionFactorToSIConversionUnit(conversionFactorToSI),
m_epsilon(epsilon), m_multiplier(multiplier)
{
// void
}
@@ -105,9 +105,9 @@ CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &unitName,
* Copy constructor
*/
CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &otherUnit):
_name(otherUnit._name), _unitName(otherUnit._unitName), _type(otherUnit._type), _isSIUnit(otherUnit._isSIUnit),
_isSIBaseUnit(otherUnit._isSIBaseUnit), _displayDigits(otherUnit._displayDigits),_conversionFactorToSIConversionUnit(otherUnit._conversionFactorToSIConversionUnit),
_epsilon(otherUnit._epsilon), _multiplier(otherUnit._multiplier)
m_name(otherUnit.m_name), m_unitName(otherUnit.m_unitName), m_type(otherUnit.m_type), m_isSIUnit(otherUnit.m_isSIUnit),
m_isSIBaseUnit(otherUnit.m_isSIBaseUnit), m_displayDigits(otherUnit.m_displayDigits),m_conversionFactorToSIConversionUnit(otherUnit.m_conversionFactorToSIConversionUnit),
m_epsilon(otherUnit.m_epsilon), m_multiplier(otherUnit.m_multiplier)
{
// void
}
@@ -118,15 +118,15 @@ CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &otherUnit):
CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &otherUnit)
{
if (this == &otherUnit) return *this; // Same object? Yes, so skip assignment, and just return *this
this->_name = otherUnit._name;
this->_unitName =otherUnit._unitName;
this->_type=otherUnit._type;
this->_isSIUnit =otherUnit._isSIUnit;
this->_isSIBaseUnit =otherUnit._isSIBaseUnit;
this->_conversionFactorToSIConversionUnit=otherUnit._conversionFactorToSIConversionUnit;
this->_multiplier = otherUnit._multiplier;
this->_displayDigits=otherUnit._displayDigits;
this->_epsilon= otherUnit._epsilon;
this->m_name = otherUnit.m_name;
this->m_unitName =otherUnit.m_unitName;
this->m_type=otherUnit.m_type;
this->m_isSIUnit =otherUnit.m_isSIUnit;
this->m_isSIBaseUnit =otherUnit.m_isSIBaseUnit;
this->m_conversionFactorToSIConversionUnit=otherUnit.m_conversionFactorToSIConversionUnit;
this->m_multiplier = otherUnit.m_multiplier;
this->m_displayDigits=otherUnit.m_displayDigits;
this->m_epsilon= otherUnit.m_epsilon;
return *this;
}
@@ -136,9 +136,9 @@ CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &otherUnit
bool CMeasurementUnit::operator ==(const CMeasurementUnit &otherUnit) const
{
if ( this == &otherUnit ) return true;
if ( this->_type != otherUnit._type) return false;
return this->_multiplier == otherUnit._multiplier && this->_name == otherUnit._name
&& this->_isSIUnit==otherUnit._isSIUnit;
if ( this->m_type != otherUnit.m_type) return false;
return this->m_multiplier == otherUnit.m_multiplier && this->m_name == otherUnit.m_name
&& this->m_isSIUnit==otherUnit.m_isSIUnit;
}
/**
@@ -146,7 +146,7 @@ bool CMeasurementUnit::operator ==(const CMeasurementUnit &otherUnit) const
*/
QDebug operator <<(QDebug d, const CMeasurementUnit &unit)
{
d << unit._name;
d << unit.m_name;
return d;
}
@@ -155,7 +155,7 @@ QDebug operator <<(QDebug d, const CMeasurementUnit &unit)
*/
CLogMessage operator<<(CLogMessage log, const CMeasurementUnit &unit)
{
log << unit._name;
log << unit.m_name;
return log;
}
@@ -170,19 +170,49 @@ bool CMeasurementUnit::operator !=(const CMeasurementUnit &otherUnit) const
/**
* Conversion factor from unit x to y
*/
double CMeasurementUnit::conversionFactor(const CMeasurementUnit &to) const
double CMeasurementUnit::conversionToUnit(double value, const CMeasurementUnit &to) const
{
return CMeasurementUnit::conversionFactor(*this, to);
if (to == (*this)) return value;
double siValue = this->convertToSiConversionUnit(value);
return to.convertFromSiConversionUnit(siValue);
}
/*!
* Value to QString with unit, e.g. "5.00m"
* @return
*/
QString CMeasurementUnit::valueRoundedWithUnit(double value, int digits) const {
return this->toQStringRounded(value, digits).append(this->getUnitName());
}
/*!
* Value rounded
*/
double CMeasurementUnit::valueRounded(double value, int digits) const {
if (digits < 0) digits = this->m_displayDigits;
return CMeasurementUnit::round(value, digits);
}
/**
* Conversion factor from unit x to y
* Rounded to QString
*/
double CMeasurementUnit::conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to)
QString CMeasurementUnit::toQStringRounded(double value, int digits) const
{
if (from == to) return 1.0;
double cf = from._conversionFactorToSIConversionUnit / to._conversionFactorToSIConversionUnit;
return cf;
if (digits < 0) digits = this->m_displayDigits;
double v = CMeasurementUnit::round(value, digits);
QString s = QLocale::system().toString(v, 'f', digits);
return s;
}
} // namespace BlackCore
/**
* Round utility method
*/
double CMeasurementUnit::round(double value, int digits) {
// gosh, is there no Qt method for this???
// It's year 2013
double m = pow(10.0,digits);
double rv = double(qRound(value * m) / m);
return rv;
}
} // namespace

View File

@@ -36,9 +36,9 @@ class CMeasurementPrefix {
friend CLogMessage operator<<(CLogMessage log, const CMeasurementPrefix &multiplier);
private:
QString _name; //!< name, e.g. "kilo"
QString _prefix; //!< prefix, e.g. "k" for kilo
double _factor; //!< factor, e.g. 1000 for kilo 1/100 for centi
QString m_name; //!< name, e.g. "kilo"
QString m_prefix; //!< prefix, e.g. "k" for kilo
double m_factor; //!< factor, e.g. 1000 for kilo 1/100 for centi
/*!
* Constructor by parameters
* \brief CMeasurementMultiplier
@@ -86,26 +86,26 @@ public:
/*!
* \brief Cast as double
*/
operator double() const { return this->_factor; }
operator double() const { return this->m_factor; }
/*!
* \brief Cast as QString
*/
operator QString() const { return this->_name;}
operator QString() const { return this->m_name;}
/*!
* \brief Factor, e.g.1000 for "kilo"
* \return
*/
double getFactor() const { return this->_factor;}
double getFactor() const { return this->m_factor;}
/*!
* \brief Name, e.g. "kilo"
* \return
*/
QString getName() const { return this->_name; }
QString getName() const { return this->m_name; }
/*!
* \brief Prefix, e.g. "k" for "kilo"
* \return
*/
QString getPrefix() const { return this->_prefix; }
QString getPrefix() const { return this->m_prefix; }
// --- static units, always use these for initialization
// --- Remark: Static initialization in C++ is random, this is why no static members
@@ -115,37 +115,43 @@ public:
* \brief Unit "None"
* \return
*/
static CMeasurementPrefix& None() { static CMeasurementPrefix none("", "", 0.0); return none;}
static const CMeasurementPrefix& None() { static CMeasurementPrefix none("", "", 0.0); return none;}
/*!
* \brief Unit "One"
* \return
*/
static CMeasurementPrefix& One() { static CMeasurementPrefix one("one", "", 1.0); return one;}
static const CMeasurementPrefix& One() { static CMeasurementPrefix one("one", "", 1.0); return one;}
/*!
* \brief Unit "mega"
* \return
*/
static CMeasurementPrefix& M() { static CMeasurementPrefix mega("mega", "M", 1E6); return mega;}
static const CMeasurementPrefix& M() { static CMeasurementPrefix mega("mega", "M", 1E6); return mega;}
/*!
* \brief Unit "kilo"
* \return
*/
static CMeasurementPrefix& k() { static CMeasurementPrefix kilo("kilo", "k", 1000.0); return kilo;}
static const CMeasurementPrefix& k() { static CMeasurementPrefix kilo("kilo", "k", 1000.0); return kilo;}
/*!
* \brief Unit "giga"
* \return
*/
static CMeasurementPrefix& G() { static CMeasurementPrefix giga("giga", "G", 1E9); return giga;}
static const CMeasurementPrefix& G() { static CMeasurementPrefix giga("giga", "G", 1E9); return giga;}
/*!
* \brief Unit "hecto"
* \return
*/
static CMeasurementPrefix& h() { static CMeasurementPrefix hecto("hecto", "h", 100.0); return hecto;}
static const CMeasurementPrefix& h() { static CMeasurementPrefix hecto("hecto", "h", 100.0); return hecto;}
/*!
* \brief Unit "centi"
* \return
*/
static CMeasurementPrefix& c() { static CMeasurementPrefix centi("centi", "c", 0.01); return centi;}
static const CMeasurementPrefix& c() { static CMeasurementPrefix centi("centi", "c", 0.01); return centi;}
/*!
* \brief Unit "milli"
* \return
*/
static const CMeasurementPrefix& m() { static CMeasurementPrefix milli("milli", "m", 1E-03); return milli;}
};
// ---------------------------------------------------------------------------------
@@ -174,20 +180,19 @@ class CMeasurementUnit {
friend CLogMessage operator<<(CLogMessage log, const CMeasurementUnit &unit);
private:
QString _name; //!< name, e.g. "meter"
QString _unitName; //!< unit name, e.g. "m"
QString _type; //!< type,such as distance. Somehow redundant, but simplifies unit comparisons
bool _isSIUnit; //!< is this a SI unit?
bool _isSIBaseUnit; //!< SI base unit?
double _conversionFactorToSIConversionUnit; //!< factor to convert to SI, set to 0 if not applicable (rare cases, e.g. temperature)
double _epsilon; //!< values with differences below epsilon are the equal
qint32 _displayDigits; //!< standard rounding dor string conversions
CMeasurementPrefix _multiplier; //!< multiplier
QString m_name; //!< name, e.g. "meter"
QString m_unitName; //!< unit name, e.g. "m"
QString m_type; //!< type,such as distance. Somehow redundant, but simplifies unit comparisons
bool m_isSIUnit; //!< is this a SI unit?
bool m_isSIBaseUnit; //!< SI base unit?
double m_conversionFactorToSIConversionUnit; //!< factor to convert to SI, set to 0 if not applicable (rare cases, e.g. temperature)
double m_epsilon; //!< values with differences below epsilon are the equal
qint32 m_displayDigits; //!< standard rounding dor string conversions
CMeasurementPrefix m_multiplier; //!< multiplier (kilo, Mega)
protected:
/*!
* Constructor by parameter
*\brief CMeasurementUnit
* \param name
* \param unitName
* \param isSIUnit
@@ -209,6 +214,12 @@ protected:
* \return
*/
CMeasurementUnit &operator =(const CMeasurementUnit &otherUnit);
protected:
/*!
* \brief Conversion factor to SI conversion unit
* \return
*/
double getConversionFactorToSI() const { return this->m_conversionFactorToSIConversionUnit; }
public:
/*!
@@ -227,65 +238,101 @@ public:
* \brief Representing an SI unit? Examples: kilometer, meter, hertz
* \return
*/
bool isSiUnit() const { return this->_isSIUnit;}
bool isSiUnit() const { return this->m_isSIUnit;}
/*!
* \brief Representing an base SI unit? Examples: second, meter
* \return
*/
bool isSiBaseUnit() const { return this->_isSIUnit;}
bool isSiBaseUnit() const { return this->m_isSIUnit;}
/*!
* \brief Representing an SI base unit? Example: meter
* \return
*/
bool isUnprefixedSiUnit() const { return this->_isSIUnit && this->_multiplier.getFactor() == 1; }
bool isUnprefixedSiUnit() const { return this->m_isSIUnit && this->m_multiplier.getFactor() == 1; }
/*!
* \brief Name such as "meter"
* \return
*/
QString getName() const { return this->_name; }
QString getName() const { return this->m_name; }
/*!
* \brief Unit name such as "m"
* \return
*/
QString getUnitName() const { return this->_unitName; }
/*!
* \brief Factor toconvert to SI unit (e.g.meter,hertz)
* \return
*/
QString getType() const { return this->_type; }
QString getUnitName() const { return this->m_unitName; }
/*!
* \brief Type such as "distance", "frequency"
* \return
*/
double getConversionFactorToSIConversionUnit() const { return this->_conversionFactorToSIConversionUnit;}
QString getType() const { return this->m_type; }
/*!
* Given value to conversion SI conversion unit (e.g. meter, hertz).
* Standard implementaion is simply factor based.
* \param value
* \return
*/
virtual double convertToSiConversionUnit(double value) const { return value * this->m_conversionFactorToSIConversionUnit; }
/*!
* \brief Value from SI conversion unit to this unit.
* Standard implementaion is simply factor based.
* \param value
* \return
*/
virtual double convertFromSiConversionUnit(double value) const { return value / this->m_conversionFactorToSIConversionUnit; }
/*!
* Rounded string utility method, virtual so units can have
* specialized formatting
* \param value
* \param digits
* \return
*/
virtual QString toQStringRounded(double value, int digits =-1) const;
/*!
* \brief Rounded value
* \param value
* \param digits
* \return
*/
double valueRounded(double value, int digits = -1) const;
/*!
* \brief Value rounded with unit, e.g. "5.00m", "30kHz"
* \param value
* \param digits
* \return
*/
virtual QString valueRoundedWithUnit(double value, int digits = -1) const;
/*!
* \brief Threshold for rounding
* \return
*/
double getEpsilon() const { return this->_epsilon;}
double getEpsilon() const { return this->m_epsilon;}
/*!
* \brief getDisplayDigits
* \return
*/
qint32 getDisplayDigits() const { return this->_displayDigits; }
qint32 getDisplayDigits() const { return this->m_displayDigits; }
/*!
* \brief Multiplier such as "kilo"
* \return
*/
CMeasurementPrefix getMultiplier() const { return this->_multiplier; }
CMeasurementPrefix getMultiplier() const { return this->m_multiplier; }
/*!
* \brief Factor to convert to given unit
* \param to
* \return
*/
double conversionFactor(const CMeasurementUnit &to) const;
double conversionToUnit(double value, const CMeasurementUnit &to) const;
// --------------------------------------------------------------------
// -- static
// --------------------------------------------------------------------
/*!
* \brief Factor to convert between given units
* \param from
* \param to
* \brief Utility round method
* \param value
* \param digits
* \return
*/
static double conversionFactor(const CMeasurementUnit &from, const CMeasurementUnit &to);
static double round(double value, int digits);
/*!
* \brief Unit is not specified
* \return
@@ -293,6 +340,6 @@ public:
static CMeasurementUnit& None() { static CMeasurementUnit none("none", "", "", false, false, 0.0, CMeasurementPrefix::None(), 0, 0); return none;}
};
} // namespace BlackMisc
} // namespace
#endif // PQBASE_H

View File

@@ -5,8 +5,8 @@ namespace BlackMisc {
/**
* Constructor by integer
*/
template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit, const CPhysicalQuantityUnitConverter unitConverter) :
m_unit(unit), m_conversionSiUnit(siConversionUnit), m_unitConverter(unitConverter)
template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit) :
m_unit(unit), m_conversionSiUnit(siConversionUnit)
{
this->setUnitValue(baseValue);
}
@@ -14,8 +14,8 @@ template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(qint32
/**
* Constructor by double
*/
template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit, const CPhysicalQuantityUnitConverter unitConverter) :
m_unit(unit), m_conversionSiUnit(siConversionUnit),m_unitConverter(unitConverter)
template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit) :
m_unit(unit), m_conversionSiUnit(siConversionUnit)
{
this->setUnitValue(baseValue);
}
@@ -25,7 +25,7 @@ template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(double
*/
template <class MU, class PQ> CPhysicalQuantity<MU,PQ>::CPhysicalQuantity(const CPhysicalQuantity &otherQuantity) :
m_unitValueD(otherQuantity.m_unitValueD), m_unitValueI(otherQuantity.m_unitValueI), m_convertedSiUnitValueD(otherQuantity.m_convertedSiUnitValueD),
m_isIntegerBaseValue(otherQuantity.m_isIntegerBaseValue), m_unit(otherQuantity.m_unit), m_conversionSiUnit(otherQuantity.m_conversionSiUnit), m_unitConverter(otherQuantity.m_unitConverter)
m_isIntegerBaseValue(otherQuantity.m_isIntegerBaseValue), m_unit(otherQuantity.m_unit), m_conversionSiUnit(otherQuantity.m_conversionSiUnit)
{
// void
}
@@ -46,7 +46,7 @@ template <class MU, class PQ> bool CPhysicalQuantity<MU,PQ>::operator ==(const C
if(this == &otherQuantity) return true;
if(this->m_unit.getType()!= otherQuantity.m_unit.getType()) return false;
// some special case for best quality
// some special cases for best quality
double diff;
const double lenient = 1.001; // even diff already has a rounding issue to be avoided
if (this->m_unit == otherQuantity.m_unit) {
@@ -87,7 +87,6 @@ template <class MU, class PQ> CPhysicalQuantity<MU,PQ>& CPhysicalQuantity<MU,PQ>
this->m_isIntegerBaseValue = otherQuantity.m_isIntegerBaseValue;
this->m_unit = otherQuantity.m_unit;
this->m_conversionSiUnit = otherQuantity.m_conversionSiUnit;
this->m_unitConverter = otherQuantity.m_unitConverter;
return *this;
}
@@ -249,7 +248,7 @@ template <class MU, class PQ> bool CPhysicalQuantity<MU,PQ>::switchUnit(const MU
{
if (this->m_unit == newUnit) return true;
if (this->m_unit.getType() != newUnit.getType()) return false; // not possible
double cf = this->m_unitConverter(this, newUnit);
double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit);
this->m_unit = newUnit;
this->setUnitValue(cf);
return true;
@@ -281,17 +280,7 @@ template <class MU, class PQ> void CPhysicalQuantity<MU,PQ>::setUnitValue(double
* Set SI value
*/
template <class MU, class PQ> void CPhysicalQuantity<MU,PQ>::setConversionSiUnitValue() {
this->m_convertedSiUnitValueD = this->m_unitConverter(this, this->m_conversionSiUnit);
}
/**
* Standard conversion by factor, used in most cases, in some cases (e.g. CTemperature) arbitrary converter
*/
template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::standardUnitFactorValueConverter(const CPhysicalQuantity<MU,PQ> *quantity, const MU &otherUnit) {
if (quantity->m_unit == MU::None() || quantity->m_unitValueD == 0.0) return 0.0;
if (quantity->m_unit == otherUnit) return quantity->m_unitValueD;
double f = quantity->m_unit.conversionFactor(otherUnit);
return f * quantity->m_unitValueD;
this->m_convertedSiUnitValueD = this->m_unit.convertToSiConversionUnit(this->m_unitValueD);
}
/**
@@ -299,18 +288,7 @@ template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::standardUnitFacto
*/
template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::unitValueToDoubleRounded(int digits) const
{
if (digits < 1) digits = this->m_unit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::round(this->m_unitValueD, digits);
}
/**
* Rounded to QString
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::toQStringRounded(double value, int digits)
{
double v =CPhysicalQuantity<MU,PQ>::round(value, digits);
QString s = QLocale::system().toString(v, 'f', digits);
return s;
return this->m_unit.valueRounded(this->m_unitValueD, digits);
}
/**
@@ -318,8 +296,15 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::toQStringRounded
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::unitValueToQStringRounded(int digits) const
{
if (digits < 1) digits = this->m_unit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::toQStringRounded(this->m_unitValueD, digits);
return this->m_unit.toQStringRounded(this->m_unitValueD, digits);
}
/**
* Rounded with unit
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::unitValueRoundedWithUnit(int digits) const
{
return this->m_unit.valueRoundedWithUnit(this->m_unitValueD, digits);
}
/**
@@ -328,15 +313,7 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::unitValueToQStri
template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::convertedSiValueToQStringRounded(int digits) const
{
if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::toQStringRounded(this->m_convertedSiUnitValueD, digits);
}
/**
* Value rounded in original unit
*/
template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::unitValueRoundedWithUnit(int digits) const {
if (digits < 1) digits = this->m_unit.getDisplayDigits();
return this->unitValueToQStringRounded(digits).append(this->m_unit.getUnitName());
return this->m_conversionSiUnit.toQStringRounded(this->m_convertedSiUnitValueD, digits);
}
/**
@@ -354,8 +331,7 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::valueRoundedWith
{
if (unit == this->m_unit) return this->unitValueRoundedWithUnit(digits);
if (unit == this->m_conversionSiUnit) return this->convertedSiValueRoundedWithUnit(digits);
if (digits < 0) digits = unit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::toQStringRounded(this->value(unit), digits).append(unit.getUnitName());
return unit.valueRoundedWithUnit(this->value(unit),digits);
}
/**
@@ -363,8 +339,7 @@ template <class MU, class PQ> QString CPhysicalQuantity<MU,PQ>::valueRoundedWith
*/
template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::valueRounded(const MU &unit, int digits) const
{
if (digits < 1) digits = unit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::round(this->value(unit),digits);
return unit.valueRounded(this->value(unit),digits);
}
/**
@@ -372,8 +347,9 @@ template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::valueRounded(cons
*/
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 = this->m_unitConverter(this, unit);
double v = unit.convertFromSiConversionUnit(this->m_convertedSiUnitValueD);
return v;
}
@@ -383,21 +359,11 @@ template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::value(const MU &u
template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::convertedSiValueToDoubleRounded(int digits) const
{
if (digits < 1) digits = this->m_conversionSiUnit.getDisplayDigits();
return CPhysicalQuantity<MU,PQ>::round(this->m_convertedSiUnitValueD, digits);
return this->m_conversionSiUnit.valueRounded(this->m_convertedSiUnitValueD, digits);
}
/**
* Round utility method
*/
template <class MU, class PQ> double CPhysicalQuantity<MU,PQ>::round(double value, int digits) {
// gosh, is there no Qt method for this???
// It's year 2013
double m = pow(10.0,digits);
double rv = double(qRound(value * m) / m);
return rv;
}
// see here for the reason of this forward initialization
// see here for the reason of this forward instants
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CPhysicalQuantity<CLengthUnit, CLength>;
template class CPhysicalQuantity<CPressureUnit, CPressure>;
@@ -406,5 +372,7 @@ template class CPhysicalQuantity<CMassUnit, CMass>;
template class CPhysicalQuantity<CTemperatureUnit, CTemperature>;
template class CPhysicalQuantity<CSpeedUnit, CSpeed>;
template class CPhysicalQuantity<CAngleUnit, CAngle>;
template class CPhysicalQuantity<CTimeUnit, CTime>;
} // namespace

View File

@@ -23,7 +23,7 @@ template <class MU, class PQ> class CPhysicalQuantity
* Our converter function, should be implemented as static method of the quantity
* classes for clarity
*/
typedef double (*CPhysicalQuantityUnitConverter)(const CPhysicalQuantity<MU,PQ> *quantity, const MU &unit);
typedef double (*CPhysicalQuantityUnitConverter)(const PQ *quantity, const MU &unit);
/*!
* Stream operator for debugging
@@ -31,9 +31,9 @@ template <class MU, class PQ> class CPhysicalQuantity
* \param debug
* \param quantity
* \return
* \remarks has to be in the header files toavoid templatelink errors
* \remarks Has to be in the header files to avoid template link errors
*/
friend QDebug operator<<(QDebug debug, const CPhysicalQuantity<MU,PQ> &quantity) {
friend QDebug operator<<(QDebug debug, const CPhysicalQuantity &quantity) {
QString v = quantity.unitValueRoundedWithUnit(-1);
debug << v;
return debug;
@@ -45,9 +45,9 @@ template <class MU, class PQ> class CPhysicalQuantity
* \param log
* \param quantity
* \return
* \remarks has to be in the header files toavoid templatelink errors
* \remarks Has to be in the header files toavoid templatelink errors
*/
friend CLogMessage operator<<(CLogMessage log, const CPhysicalQuantity<MU,PQ> &quantity) {
friend CLogMessage operator<<(CLogMessage log, const CPhysicalQuantity &quantity) {
QString v = quantity.unitValueRoundedWithUnit(-1);
log << v;
return log;
@@ -58,16 +58,6 @@ private:
double m_unitValueD; //!< value backed by double
double m_convertedSiUnitValueD; //!< SI unit value
bool m_isIntegerBaseValue; //!< flag integer? / double?
CPhysicalQuantityUnitConverter m_unitConverter; //! <! converts values between units
/*!
* Convert value in another unit, normally just by a factor, but in some cases
* (e.g. CTemperature) overridden, because arbitrary conversion is required
* \param quantity quanity
* \param otherUnit
* \return
*/
static double standardUnitFactorValueConverter(const CPhysicalQuantity<MU,PQ> *quantity, const MU &otherUnit);
protected:
MU m_unit; //!< unit
@@ -80,16 +70,14 @@ protected:
* \param siBaseUnit
* \param unitConverter
*/
CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit,
const CPhysicalQuantityUnitConverter unitConverter = CPhysicalQuantity::standardUnitFactorValueConverter);
CPhysicalQuantity(qint32 baseValue, const MU &unit, const MU &siConversionUnit);
/*!
* \brief Constructor with double
* \param baseValue
* \param unit
* \param siBaseUnit
*/
CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit,
const CPhysicalQuantityUnitConverter unitConverter = CPhysicalQuantity::standardUnitFactorValueConverter);
CPhysicalQuantity(double baseValue, const MU &unit, const MU &siConversionUnit);
/*!
* \brief Init by integer
* \param baseValue
@@ -110,11 +98,11 @@ public:
* \brief Copy constructor
* \param otherQuantity
*/
CPhysicalQuantity<MU,PQ>(const CPhysicalQuantity<MU,PQ> &otherQuantity);
CPhysicalQuantity(const CPhysicalQuantity &otherQuantity);
/*!
* \brief Virtual destructor
*/
virtual ~CPhysicalQuantity<MU,PQ>();
virtual ~CPhysicalQuantity();
/*!
* \brief Unit of the distance
* \return
@@ -146,12 +134,6 @@ public:
* \return
*/
bool isUnprefixedSiUnit() const { return this->m_unit.isUnprefixedSiUnit(); }
/*!
* \brief Value to QString with unit, e.g. "5.00m"
* \param digits
* @return
*/
QString unitValueRoundedWithUnit(int digits = -1) const;
/*!
* \brief Value in given unit
* \param unit
@@ -182,11 +164,17 @@ public:
* @return
*/
double unitValueToDouble() const { return this->m_unitValueD;}
/*!
* \brief Value to QString with unit, e.g. "5.00m"
* \param digits
* @return
*/
QString unitValueRoundedWithUnit(int digits = -1) const;
/*!
* \brief SI value to integer
* @return
*/
qint32 siBaseUnitValueToInteger() const { return CPhysicalQuantity::round(this->m_convertedSiUnitValueD,0);}
qint32 siBaseUnitValueToInteger() const { return CMeasurementUnit::round(this->m_convertedSiUnitValueD,0);}
/*!
* \brief SI value to double
* @return
@@ -213,7 +201,7 @@ public:
* \brief SI value as integer
* \return
*/
qint32 convertedSiValueToInteger() const { return (qint32)CPhysicalQuantity::round(this->m_convertedSiUnitValueD,0);}
qint32 convertedSiValueToInteger() const { return static_cast<qint32>(CMeasurementUnit::round(this->m_convertedSiUnitValueD,0));}
/*!
* \brief Rounded SI value by n digits
* \param digits
@@ -258,13 +246,13 @@ public:
* \param multiply
* \return
*/
CPhysicalQuantity<MU,PQ> &operator *=(double multiply);
CPhysicalQuantity &operator *=(double multiply);
/*!
* \brief Divide operator /=
* \param divide
* @return
*/
CPhysicalQuantity<MU,PQ> &operator /=(double divide);
CPhysicalQuantity &operator /=(double divide);
/*!
* \brief Operator *
* \param multiply
@@ -282,55 +270,55 @@ public:
* \param otherQuantity
* @return
*/
bool operator==(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator==(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Not equal operator !=
* \param otherQuantity
* @return
*/
bool operator!=(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator!=(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Plus operator +=
* \param otherQuantity
* @return
*/
CPhysicalQuantity<MU,PQ> &operator +=(const CPhysicalQuantity<MU,PQ> &otherQuantity);
CPhysicalQuantity &operator +=(const CPhysicalQuantity &otherQuantity);
/*!
* \brief Minus operator-=
* \param otherQuantity
* @return
*/
CPhysicalQuantity<MU,PQ> &operator -=(const CPhysicalQuantity<MU,PQ> &otherQuantity);
CPhysicalQuantity &operator -=(const CPhysicalQuantity &otherQuantity);
/*!
* \brief Greater operator >
* \param otherQuantity
* @return
*/
bool operator >(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator >(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Less operator <
* \param otherQuantity
* @return
*/
bool operator <(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator <(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Less equal operator <=
* \param otherQuantity
* @return
*/
bool operator <=(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator <=(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Greater equal operator >=
* \param otherQuantity
* @return
*/
bool operator >=(const CPhysicalQuantity<MU,PQ> &otherQuantity) const;
bool operator >=(const CPhysicalQuantity &otherQuantity) const;
/*!
* \brief Assignment operator =
* \param otherQuantity
* @return
*/
CPhysicalQuantity<MU,PQ> &operator =(const CPhysicalQuantity<MU,PQ> &otherQuantity);
CPhysicalQuantity &operator =(const CPhysicalQuantity &otherQuantity);
/*!
* \brief Plus operator +
* \param otherQuantity
@@ -344,26 +332,6 @@ public:
*/
PQ operator -(const PQ &otherQuantity) const;
// --------------------------------------------------------------------
// -- static
// --------------------------------------------------------------------
/*!
* \brief Utility round method
* \param value
* \param digits
* \return
*/
static double round(double value, int digits);
/*!
* \brief Rounded string utility method
* \param value
* \param digits
* \return
*/
static QString toQStringRounded(double value, int digits);
};
} // namespace BlackCore

View File

@@ -1,40 +0,0 @@
#include "blackmisc/pqtemperature.h"
namespace BlackMisc {
/**
* Specialized method for temperture
*/
double CTemperature::temperaturUnitConverter(const CPhysicalQuantity<CTemperatureUnit, CTemperature> *quantity, const CTemperatureUnit &otherUnit)
{
CTemperature *me = (CTemperature*) quantity; // allow me access to protected
if (me->m_unit == otherUnit) return me->siBaseUnitValueToDouble();
double siValue;
// I always convert via SI Unit, other I would need too many conversions
if(otherUnit == me->m_conversionSiUnit) {
// here I expect a conversion to SI is required and not done yet
if(me->m_unit == CTemperatureUnit::C()) {
siValue = quantity->unitValueToDouble() + 273.15;
} else if(me->m_unit == CTemperatureUnit::F()) {
siValue = (me->unitValueToDouble() + 459.67) *5.0 / 9.0;
} else{
// TODO: EXCEPTION
}
} else {
// here I expect the SI value is already set
siValue = quantity->siBaseUnitValueToDouble();
}
// from SI
if (otherUnit == me->m_conversionSiUnit) return siValue;
if(otherUnit == CTemperatureUnit::C()) {
return siValue - 273.15;
} else if(me->m_unit == CTemperatureUnit::F()) {
return (siValue * 9.0 / 5.0) - 459.67;
}
// TODO: Exception
return 0;
}
} // namespace

View File

@@ -10,20 +10,11 @@ namespace BlackMisc {
*/
class CTemperature : public CPhysicalQuantity<CTemperatureUnit,CTemperature>
{
private:
/*!
* \brief Convert into another temperature unit
* \param quantity
* \param otherUnit
* \return
*/
static double temperaturUnitConverter(const CPhysicalQuantity<CTemperatureUnit,CTemperature> *quantity, const CTemperatureUnit &otherUnit);
public:
/*!
* \brief Default constructor
*/
CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::K(), CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {}
CTemperature() : CPhysicalQuantity(0, CTemperatureUnit::K(), CTemperatureUnit::K()) {}
/**
*\brief Copy constructor
*/
@@ -33,13 +24,13 @@ public:
* \param value
* \param unit
*/
CTemperature(qint32 value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {}
CTemperature(qint32 value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K()) {}
/*!
*\brief Init by double value
* \param value
* \param unit
*/
CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K(), CTemperature::temperaturUnitConverter) {}
CTemperature(double value, const CTemperatureUnit &unit): CPhysicalQuantity(value, unit, CTemperatureUnit::K()) {}
/*!
* \brief Destructor
*/

43
src/blackmisc/pqtime.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef PQTIME_H
#define PQTIME_H
#include "pqphysicalquantity.h"
namespace BlackMisc {
/*!
* Time class, e.g. "ms", "hour", "s", "day"
* \author KWB
*/
class CTime : public CPhysicalQuantity<CTimeUnit, CTime>
{
public:
/*!
* \brief Default constructor
*/
CTime() : CPhysicalQuantity(0, CTimeUnit::s(), CTimeUnit::s()) {}
/**
*\brief Copy constructor
*/
CTime(const CPhysicalQuantity &time): CPhysicalQuantity(time) {}
/*!
* \brief Init by int value
* \param value
* \param unit
*/
CTime(qint32 value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit, CTimeUnit::s()) {}
/*!
*\brief Init by double value
* \param value
* \param unit
*/
CTime(double value, const CTimeUnit &unit) : CPhysicalQuantity(value, unit, CTimeUnit::s()) {}
/*!
* \brief Destructor
*/
virtual ~CTime() {}
};
} // namespace
#endif // PQTIME_H

90
src/blackmisc/pqunits.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "blackmisc/pqunits.h"
namespace BlackMisc {
/**
* Convert to SI
*/
double CTemperatureUnit::convertToSiConversionUnit(double value) const
{
double v = value + this->m_conversionOffsetToSi;
v *= this->getConversionFactorToSI();
return v;
}
/**
* Convert from SI
*/
double CTemperatureUnit::convertFromSiConversionUnit(double value) const
{
double v = value / this->getConversionFactorToSI();
v -= this->m_conversionOffsetToSi;
return v;
}
/**
* Convert from SI
*/
double CAngleUnit::convertFromSiConversionUnit(double value) const
{
double v;
// still a design flaw since I have to distinguish as per type
// but an own converter per object was really too much
if ((*this) == CAngleUnit::sexagesimalDeg()) {
value = value * 180 / M_PI; // degree
v = floor(value);
double c = value - v;
double mr = c * 60.0;
double m = floor(mr); // minutes
double s = (mr-m) * 60; // seconds + rest fraction
v = (v + (m/100) + (s/10000));
} else {
v = CMeasurementUnit::convertFromSiConversionUnit(value);
}
return v;
}
/**
* Convert to SI
*/
double CAngleUnit::convertToSiConversionUnit(double value) const
{
// still a design flaw since I have to distinguish as per type
// but an own converter per object was really too much
double v;
if ((*this) == CAngleUnit::sexagesimalDeg()) {
double v = floor(value); // degrees
double c = value - v;
c = c * 100.0;
double m = floor(c);
c = c - m;
m /= 60.0; // minutes back to decimals
double s = c / 36.0; // seconds back to decimals
v = v + m + s;
return v / 180.0 * M_PI;
} else {
v = CMeasurementUnit::convertToSiConversionUnit(value);
}
return v;
}
/**
* Rounded to QString
*/
QString CAngleUnit::toQStringRounded(double value, int digits) const
{
QString s;
if ((*this) == CAngleUnit::sexagesimalDeg()) {
double de = floor(value);
double mi = floor((value-de)*100.0);
double se = floor((value-de-mi/100.0)*1000000) / 100.0;
QString ses = QLocale::system().toString(se, 'f', 2);
s = QString::number(de).append(this->getUnitName()).append(QString::number(mi))
.append("'").append(ses).append("\"");
} else {
s = CMeasurementUnit::toQStringRounded(value, digits);
}
return s;
}
}

View File

@@ -1,18 +1,22 @@
#ifndef PQUNITS_H
#define PQUNITS_H
#include "blackmisc/pqbase.h"
#include <math.h>
//
// Used with the template for quantities. This is the reason for
// having all units in one file, since template requires concrete instantiations
//
namespace BlackMisc {
/*!
* Specialized class for distance units (meter, foot, nautical miles).
* \author KWB
* \author KWB, MS
*/
class CLengthUnit : public CMeasurementUnit {
private:
/*!
* Constructor
* \brief Distance unit
* \brief Constructor Distance unit
* \param name
* \param unitName
* \param isSIUnit
@@ -66,8 +70,7 @@ public:
class CAngleUnit : public CMeasurementUnit {
private:
/*!
* Constructor
* \brief Angle units: Radian, degree
* \brief Constructor angle units: Radian, degree
* \param name
* \param unitName
* \param isSIUnit
@@ -82,20 +85,45 @@ private:
// void
}
public:
CAngleUnit(const CAngleUnit &otherUnit) : CMeasurementUnit(otherUnit)
{
// void
}
/*!
* \brief Meter m
* \brief Copy constructor
* \param otherUnit
*/
CAngleUnit(const CAngleUnit &otherUnit) : CMeasurementUnit(otherUnit) { }
/*!
* \brief Convert to SI conversion unit, specific for angle
* \param value
* \return
*/
virtual double CAngleUnit::convertToSiConversionUnit(double value) const;
/*!
* \brief Convert from SI conversion unit, specific for angle
* \param value
* \return
*/
virtual double CAngleUnit::convertFromSiConversionUnit(double value) const;
/*!
* \brief Special conversion to QString for sexagesimal degrees.
* \param value
* \param digits
* \return
*/
virtual QString toQStringRounded(double value, int digits) const;
/*!
* \brief Radians
* \return
*/
static const CAngleUnit& rad() { static CAngleUnit rad("radian", "rad", true); return rad;}
/*!
* \brief Nautical miles NM
* \brief Degrees
* \return
*/
static const CAngleUnit& deg() { static CAngleUnit deg("degree", "°", false, M_PI/180); return deg;}
/*!
* \brief Sexagesimal degree (degree, minute, seconds)
* \return
*/
static const CAngleUnit& sexagesimalDeg() { static CAngleUnit deg("segadecimal degree", "°", false, M_PI/180); return deg;}
};
/*!
@@ -151,8 +179,7 @@ public:
class CMassUnit : public CMeasurementUnit {
private:
/*!
* Constructor
* \brief Mass units
* \brief Constructor mass units
* \param name
* \param unitName
* \param isSIUnit
@@ -183,7 +210,7 @@ public:
* \brief Tonne, aka metric tonne (1000kg)
* \return
*/
static const CMassUnit& t() { static CMassUnit t("tonne", "t", true, false, 1000.0, CMeasurementPrefix::One(), 3); return t;}
static const CMassUnit& t() { static CMassUnit t("tonne", "t", false, false, 1000.0, CMeasurementPrefix::One(), 3); return t;}
/*!
* \brief Pound, aka mass pound
* \return
@@ -257,30 +284,51 @@ public:
* \author KWB
*/
class CTemperatureUnit : public CMeasurementUnit {
private:
double m_conversionOffsetToSi;
private:
/*!
* Constructor
* \brief Temperature unit
* Constructor temperature unit
* \param name
* \param unitName
* \param isSIUnit
* \param isSIBaseUnit
* \param conversionFactorToSI
* \param temperatureOffsetToSI
* \param mulitplier
* \param displayDigits
* \param epsilon
*/
CTemperatureUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) :
CMeasurementUnit(name, unitName, "temperature", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {}
CTemperatureUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, double temperatureOffsetToSI=0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) :
CMeasurementUnit(name, unitName, "temperature", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon), m_conversionOffsetToSi(temperatureOffsetToSI) {}
public:
/*!
* \brief Copy constructor
* \param otherUnit
*/
CTemperatureUnit(const CTemperatureUnit &otherUnit) : CMeasurementUnit(otherUnit)
CTemperatureUnit(const CTemperatureUnit &otherUnit) : CMeasurementUnit(otherUnit), m_conversionOffsetToSi(otherUnit.m_conversionOffsetToSi) {}
/*!
* Assigment operator
*/
CTemperatureUnit &CTemperatureUnit::operator =(const CTemperatureUnit &otherUnit)
{
// void
if (this == &otherUnit) return *this; // Same object? Yes, so skip assignment, and just return *this
CMeasurementUnit::operator = (otherUnit);
this->m_conversionOffsetToSi = otherUnit.m_conversionOffsetToSi;
return (*this);
}
/*!
* \brief Convert to SI conversion unit, specific for temperature
* \param value
* \return
*/
virtual double CTemperatureUnit::convertToSiConversionUnit(double value) const;
/*!
* \brief Convert from SI conversion unit, specific for temperature
* \param value
* \return
*/
virtual double CTemperatureUnit::convertFromSiConversionUnit(double value) const;
/*!
* \brief Kelvin
* \return
@@ -290,12 +338,13 @@ public:
* \brief Centigrade C
* \return
*/
static const CTemperatureUnit& C() { static CTemperatureUnit C("centigrade", "°C", false, false);return C;}
static const CTemperatureUnit& C() { static CTemperatureUnit C("centigrade", "°C", false, false, 1.0, 273.15);return C;}
/*!
* \brief Fahrenheit F
* \return
*/
static const CTemperatureUnit& F() { static CTemperatureUnit F("Fahrenheit", "°F", false, false, 5.0/9.0);return F;}
static const CTemperatureUnit& F() { static CTemperatureUnit F("Fahrenheit", "°F", false, false, 5.0/9.0, 459.67);return F;}
};
/*!
@@ -306,7 +355,7 @@ class CSpeedUnit : public CMeasurementUnit {
private:
/*!
* Constructor
* \brief CSpeedUnit
* \brief Speed unit constructor
* \param name
* \param unitName
* \param isSIUnit
@@ -320,7 +369,7 @@ private:
CMeasurementUnit(name, unitName, "speed", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {}
public:
/*!
* Downcast copy constructor, allows to implement methods in base class
* Constructor, allows to implement methods in base class
* \param otherUnit
*/
CSpeedUnit(const CSpeedUnit &otherUnit) : CMeasurementUnit(otherUnit) {}
@@ -351,6 +400,59 @@ public:
static const CSpeedUnit& km_h() { static CSpeedUnit kmh("kilometer/hour", "km/h", false, false, 1.0/3.6, CMeasurementPrefix::One(), 1);return kmh;}
};
/*!
* Specialized class for time units (ms, hour, min).
* \author KWB
*/
class CTimeUnit : public CMeasurementUnit {
private:
/*!
* Constructor
* \brief Time unit constructor
* \param name
* \param unitName
* \param isSIUnit
* \param isSIBaseUnit
* \param conversionFactorToSI
* \param mulitplier
* \param displayDigits
* \param epsilon
*/
CTimeUnit(const QString &name, const QString &unitName, bool isSIUnit, bool isSIBaseUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) :
CMeasurementUnit(name, unitName, "time", isSIUnit, isSIBaseUnit, conversionFactorToSI, mulitplier, displayDigits, epsilon) {}
public:
/*!
* Constructor, allows to implement methods in base class
* \param otherUnit
*/
CTimeUnit(const CTimeUnit &otherUnit) : CMeasurementUnit(otherUnit) {}
/*!
* \brief Second s
* \return
*/
static const CTimeUnit& s() { static CTimeUnit s("second", "s", true, true, 1, CMeasurementPrefix::None(), 1); return s;}
/*!
* \brief Millisecond ms
* \return
*/
static const CTimeUnit& ms() { static CTimeUnit ms("millisecond", "ms", true, false, 1E-03, CMeasurementPrefix::m(), 0); return ms;}
/*!
* \brief Hour
* \return
*/
static const CTimeUnit& h() { static CTimeUnit h("hour", "h", false, false, 3600, CMeasurementPrefix::None(), 1); return h;}
/*!
* \brief Minute
* \return
*/
static const CTimeUnit& min() { static CTimeUnit min("minute", "min", false, false, 60, CMeasurementPrefix::None(), 2); return min;}
/*!
* \brief Day
* \return
*/
static const CTimeUnit& d() { static CTimeUnit day("day", "d", false, false, 3600*24, CMeasurementPrefix::None(), 1); return day;}
};
} // namespace
#endif // PQUNITS_H

View File

@@ -4,7 +4,7 @@
/**
* @namespace BlackMiscTest
* Unit test for BlackMisc. Unit test do have their own namespace, so
* the regular namespace BlackMiscis completely free of unit tests.
* the regular namespace BlackMisc is completely free of unit tests.
* Add any new tests to TestMain::unitMain as shown there in the pattern.
*/

View File

@@ -93,9 +93,11 @@ void TestPhysicalQuantitiesBase::angleTests()
{
CAngle a1(180, CAngleUnit::deg());
CAngle a2(1.5 * CAngle::pi(), CAngleUnit::rad());
CAngle a3(35.4336,CAngleUnit::sexagesimalDeg()); // 35.72666
a2.switchUnit(CAngleUnit::deg());
QVERIFY2(a2.unitValueToInteger() == 270, qPrintable(QString("1.5Pi should be 270deg, not %1 deg").arg(a2.unitValueToInteger())));
QVERIFY2(a1.piFactor() == 1, qPrintable(QString("Pi should be 1PI,not %1").arg(a1.piFactor())));
QVERIFY2(a1.piFactor() == 1, qPrintable(QString("Pi should be 1PI, not %1").arg(a1.piFactor())));
QVERIFY2(a3.valueRounded(CAngleUnit::deg()) == 35.73, "Expecting 35.73");
}
/**
@@ -137,13 +139,24 @@ void TestPhysicalQuantitiesBase::temperatureTests()
CTemperature t1(0, CTemperatureUnit::C()); // 0C
CTemperature t2(1, CTemperatureUnit::F()); // 1F
CTemperature t3(220.15, CTemperatureUnit::F());
CTemperature t4(10, CTemperatureUnit::F());
QVERIFY2(t1.convertedSiValueToDoubleRounded() == 273.15, qPrintable(QString("0C shall be 273.15K, not %1 K").arg(t1.convertedSiValueToDoubleRounded())));
QVERIFY2(t2.valueRounded(CTemperatureUnit::C()) == -17.22, qPrintable(QString("1F shall be -17.22C, not %1 C").arg(t2.valueRounded(CTemperatureUnit::C()))));
QVERIFY2(t3.valueRounded(CTemperatureUnit::C()) == 104.53, qPrintable(QString("220.15F shall be 104.53C, not %1 C").arg(t3.valueRounded(CTemperatureUnit::C()))));
QVERIFY2(t4.valueRounded(CTemperatureUnit::K()) == 260.93, qPrintable(QString("10F shall be 260.93K, not %1 K").arg(t4.valueRounded(CTemperatureUnit::K()))));
}
/**
* @brief Just testing obvious memory create / destruct flaws
* Temperature tests
*/
void TestPhysicalQuantitiesBase::timeTests()
{
CTime t1(1, CTimeUnit::h());
QVERIFY2(t1.siBaseUnitValueToInteger() == 3600, "1hour shall be 3600s");
}
/**
* Just testing obvious memory create / destruct flaws
*/
void TestPhysicalQuantitiesBase::memoryTests()
{

View File

@@ -52,6 +52,10 @@ private slots:
* \brief Testing temperature
*/
void temperatureTests();
/*!
* \brief Testing time
*/
void timeTests();
/*!
* \brief Testing construction / destruction in memory
*/