From eb102372f115e17e2164e698a0b7765aa91c8eef Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Fri, 5 Apr 2013 02:29:52 +0200 Subject: [PATCH] Individual (per object) conversion as well as per unit (class) now possible, this is required for sexagesimal conversion (degrees) and will be required for geo-positions. Further classed for avionics. --- client.pro | 2 +- ...ies.pro => sample_quantities_avionics.pro} | 0 .../blackmiscquantities/samplesaviation.cpp | 5 + samples/blackmiscquantities/samplesaviation.h | 2 +- src/blackmisc/aviobase.h | 66 +++++++ src/blackmisc/aviocomsystem.h | 146 +++++++++++++++ src/blackmisc/aviomodulator.cpp | 64 +++++++ src/blackmisc/aviomodulator.h | 167 ++++++++++++++++++ src/blackmisc/avionbase.cpp | 12 ++ src/blackmisc/blackmisc.pro | 8 +- src/blackmisc/pqbase.cpp | 23 ++- src/blackmisc/pqbase.h | 49 +++-- src/blackmisc/pqconstants.h | 15 ++ src/blackmisc/pqphysicalquantity.cpp | 2 +- src/blackmisc/pqunits.cpp | 61 +++---- src/blackmisc/pqunits.h | 79 +++++---- tests/blackmisc/testaviationbase.cpp | 12 ++ tests/blackmisc/testaviationbase.h | 7 + 18 files changed, 622 insertions(+), 98 deletions(-) rename samples/blackmiscquantities/{sample_blackmisc_quantities.pro => sample_quantities_avionics.pro} (100%) create mode 100644 src/blackmisc/aviobase.h create mode 100644 src/blackmisc/aviocomsystem.h create mode 100644 src/blackmisc/aviomodulator.cpp create mode 100644 src/blackmisc/aviomodulator.h create mode 100644 src/blackmisc/avionbase.cpp diff --git a/client.pro b/client.pro index 489550d65..0f5af439c 100644 --- a/client.pro +++ b/client.pro @@ -47,7 +47,7 @@ equals(WITH_SAMPLES, ON) { SUBDIRS += samples/geodetic2ecef/sample_geodetic2ecef.pro SUBDIRS += samples/interpolator/sample_interpolator.pro SUBDIRS += samples/logging/sample_logging.pro - SUBDIRS += samples/blackmiscquantities/sample_blackmisc_quantities.pro + SUBDIRS += samples/blackmiscquantities/sample_quantities_avionics.pro } equals(WITH_UNITTESTS, ON) { diff --git a/samples/blackmiscquantities/sample_blackmisc_quantities.pro b/samples/blackmiscquantities/sample_quantities_avionics.pro similarity index 100% rename from samples/blackmiscquantities/sample_blackmisc_quantities.pro rename to samples/blackmiscquantities/sample_quantities_avionics.pro diff --git a/samples/blackmiscquantities/samplesaviation.cpp b/samples/blackmiscquantities/samplesaviation.cpp index 722647200..2e6aac4ed 100644 --- a/samples/blackmiscquantities/samplesaviation.cpp +++ b/samples/blackmiscquantities/samplesaviation.cpp @@ -16,6 +16,11 @@ int CSamplesAviation::samples() CAviationVerticalPositions vp2 = vp1; qDebug() << vp1 << (vp1 == vp2) << (vp1 != vp2); + CComSystem c1 = CComSystem::getCom1Unit(125.3); + qDebug() << c1; + c1.setActiveUnicom(); + qDebug() << c1; + // bye return 0; } diff --git a/samples/blackmiscquantities/samplesaviation.h b/samples/blackmiscquantities/samplesaviation.h index 1a9241665..83e7817b3 100644 --- a/samples/blackmiscquantities/samplesaviation.h +++ b/samples/blackmiscquantities/samplesaviation.h @@ -1,10 +1,10 @@ #ifndef SAMPLESAVIATION_H #define SAMPLESAVIATION_H -#include #include "blackmisc/avheading.h" #include "blackmisc/avverticalpositions.h" #include "blackmisc/pqconstants.h" +#include "blackmisc/aviocomsystem.h" using namespace BlackMisc; diff --git a/src/blackmisc/aviobase.h b/src/blackmisc/aviobase.h new file mode 100644 index 000000000..15afa9563 --- /dev/null +++ b/src/blackmisc/aviobase.h @@ -0,0 +1,66 @@ +#ifndef AVIOBASE_H +#define AVIOBASE_H + +#include "blackmisc/pqconstants.h" + +namespace BlackMisc { + +/*! + * \brief Base class for avionics + */ +class CAvionicsBase +{ + /*! + * Stream operator for debugging + * \brief operator << + * \param debug + * \param avionic + * \return + * \remarks Has to be in the header files to avoid template link errors + */ + friend QDebug operator<<(QDebug debug, const CAvionicsBase &avionic) { + QString v = avionic.stringForStreamingOperator(); + debug << v; + return debug; + } + /*! + * Stream operator for log messages + * \brief operator << + * \param log + * \param avionic + * \return + * \remarks Has to be in the header files to avoid template link errors + */ + friend CLogMessage operator<<(CLogMessage log, const CAvionicsBase &avionic) { + QString v = avionic.stringForStreamingOperator(); + log << v; + return log; + } + +protected: + /*! + * \brief Default constructor + */ + CAvionicsBase() {} + /*! + * \brief Meaningful string representation + * \return + */ + virtual QString stringForStreamingOperator() const = 0; + /*! + * \brief Are the set values valid / in range + * \return + */ + virtual bool validValues() { return true; } +public: + + /** + * @brief Virtual destructor + */ + virtual ~CAvionicsBase() {} + +}; + +} // namespace + +#endif // AVIOBASE_H diff --git a/src/blackmisc/aviocomsystem.h b/src/blackmisc/aviocomsystem.h new file mode 100644 index 000000000..11cf14ec4 --- /dev/null +++ b/src/blackmisc/aviocomsystem.h @@ -0,0 +1,146 @@ +#ifndef AVIOCOMUNIT_H +#define AVIOCOMUNIT_H +#include "blackmisc/aviomodulator.h" + +namespace BlackMisc { + +/*! + * \brief COM system (aka "radio") + */ +class CComSystem : public CModulator +{ +private: + /*! + * \brief Valid civil aviation frequency? + * \param f + * \return + */ + bool isValidCivilAviationFrequency(CFrequency f) { double fr = f.valueRounded(CFrequencyUnit::MHz(), this->m_digits); return fr >= 118.0 && fr <= 136.975; } + /*! + * \brief Valid military aviation frequency? + * \param f + * \return + */ + bool isValidMilitaryFrequency(CFrequency f) { double fr = f.valueRounded(CFrequencyUnit::MHz(), this->m_digits); return fr >= 220.0 && fr <= 399.95; } + +public: + /*! + * Default constructor + */ + CComSystem() : CModulator() {} + /*! + * \brief Copy constructor + * \param otherUnit + */ + CComSystem(const CComSystem &otherUnit) : CModulator(otherUnit) {} + /*! + * \brief Constructor + * \param name + * \param activeFrequency + * \param standbyFrequency + * \param digits + */ + CComSystem(const QString &name, const CFrequency &activeFrequency, const CFrequency &standbyFrequency, int digits =3): + CModulator(name, activeFrequency, standbyFrequency, digits) {} + /*! + * \brief Set active frequency + * \param frequencyMHz + */ + void setFrequencyActiveMHz(double frequencyMHz) { CModulator::setFrequencyActiveMHz(frequencyMHz); } + /*! + * \brief Set standby frequency + * \param frequencyMHz + */ + void setFrequencyStandbyMHz(double frequencyMHz) { CModulator::setFrequencyStandbyMHz(frequencyMHz); } + /*! + * \brief Set UNICOM frequency as active + */ + void setActiveUnicom() { this->toggleActiveStandby(); this->setFrequencyActive(CPhysicalQuantitiesConstants::FrequencyUnicom());} + /*! + * \brief Set International Air Distress 121.5MHz + */ + void setActiveInternationalAirDistress() { this->toggleActiveStandby(); this->setFrequencyActive(CPhysicalQuantitiesConstants::FrequencyInternationalAirDistress());} + /*! + * \brief Assigment operator = + * \param otherSystem + * \return + */ + CComSystem& operator =(const CComSystem &otherSystem) { CModulator::operator =(otherSystem); return (*this); } + /*! + * \brief operator == + * \param otherSystem + * \return + */ + bool operator ==(const CComSystem &otherSystem) const { return CModulator::operator ==(otherSystem); } + /*! + * \brief operator == + * \param otherSystem + * \return + */ + bool operator !=(const CComSystem &otherSystem) const { return CModulator::operator !=(otherSystem); } + + /*! + * \brief Are the set values valid / in range? + * \return + */ + virtual bool validValues() { + return + this->isValidCivilAviationFrequency(this->getFrequencyActive()) && + this->isValidMilitaryFrequency(this->getFrequencyActive()) && + this->isValidCivilAviationFrequency(this->getFrequencyStandby()) && + this->isValidMilitaryFrequency(this->getFrequencyStandby()); + } + /*! + * \brief COM1 unit + * \param activeFrequencyMHz + * \param standbyFrequencyMHz + * \return + */ + static CComSystem getCom1Unit(double activeFrequencyMHz, double standbyFrequencyMHz = -1) { + return CComSystem(CModulator::NameCom1(), CFrequency(activeFrequencyMHz, CFrequencyUnit::MHz()), CFrequency(standbyFrequencyMHz < 0 ? activeFrequencyMHz : standbyFrequencyMHz,CFrequencyUnit::MHz()));} + /*! + * \brief COM1 unit + * \param activeFrequency + * \param standbyFrequency + * \return + */ + static CComSystem getCom1Unit(CFrequency activeFrequency, CFrequency standbyFrequency = CModulator::FrequencyNotSet()) { + return CComSystem(CModulator::NameCom1(), activeFrequency, standbyFrequency == CModulator::FrequencyNotSet() ? activeFrequency : standbyFrequency);} + /*! + * \brief COM2 unit + * \param activeFrequencyMHz + * \param standbyFrequencyMHz + * \return + */ + static CComSystem getCom2Unit(double activeFrequencyMHz, double standbyFrequencyMHz = -1) { + return CComSystem(CModulator::NameCom2(), CFrequency(activeFrequencyMHz, CFrequencyUnit::MHz()), CFrequency(standbyFrequencyMHz < 0 ? activeFrequencyMHz : standbyFrequencyMHz,CFrequencyUnit::MHz()));} + /*! + * \brief COM2 unit + * \param activeFrequency + * \param standbyFrequency + * \return + */ + static CComSystem getCom2Unit(CFrequency activeFrequency, CFrequency standbyFrequency = CModulator::FrequencyNotSet()) { + return CComSystem(CModulator::NameCom2(), activeFrequency, standbyFrequency == CModulator::FrequencyNotSet() ? activeFrequency : standbyFrequency);} + /*! + * \brief COM3 unit + * \param activeFrequencyMHz + * \param standbyFrequencyMHz + * \return + */ + static CComSystem getCom3Unit(double activeFrequencyMHz, double standbyFrequencyMHz = -1) { + return CComSystem(CModulator::NameCom3(), CFrequency(activeFrequencyMHz, CFrequencyUnit::MHz()), CFrequency(standbyFrequencyMHz < 0 ? activeFrequencyMHz : standbyFrequencyMHz,CFrequencyUnit::MHz()));} + /*! + * \brief COM3 unit + * \param activeFrequency + * \param standbyFrequency + * \return + */ + static CComSystem getCom3Unit(CFrequency activeFrequency, CFrequency standbyFrequency = CModulator::FrequencyNotSet()) { + return CComSystem(CModulator::NameCom3(), activeFrequency, standbyFrequency == CModulator::FrequencyNotSet() ? activeFrequency : standbyFrequency);} + +}; + +} // namespace + +#endif // AVIOCOMUNIT_H diff --git a/src/blackmisc/aviomodulator.cpp b/src/blackmisc/aviomodulator.cpp new file mode 100644 index 000000000..d6e717912 --- /dev/null +++ b/src/blackmisc/aviomodulator.cpp @@ -0,0 +1,64 @@ +#include "blackmisc/aviomodulator.h" +#include "blackmisc/aviocomsystem.h" + +namespace BlackMisc { + +/** + * Toggle standby <-> active + */ +template void CModulator::toggleActiveStandby() +{ + CFrequency a = this->m_frequencyActive; + this->m_frequencyActive = this->m_frequencyStandby; + this->m_frequencyStandby = a; +} + +/** + * String representation + */ +template QString CModulator::stringForStreamingOperator() const +{ + QString s(this->m_name); + s.append(" Active: ").append(this->m_frequencyActive.unitValueRoundedWithUnit(3)); + s.append(" Standby: ").append(this->m_frequencyStandby.unitValueRoundedWithUnit(3)); + return s; +} + +/** + * Assigment operator = + */ +template CModulator& CModulator::operator=(const CModulator &otherModulator) { + + if (this == &otherModulator) return *this; // Same object? + this->m_frequencyActive = otherModulator.m_frequencyActive; + this->m_frequencyStandby = otherModulator.m_frequencyStandby; + this->m_name = otherModulator.m_name; + this->m_digits = otherModulator.m_digits; + return *this; +} + +/** + * Equal operator == + */ +template bool CModulator::operator ==(const CModulator &otherModulator) const +{ + if(this == &otherModulator) return true; + return (this->m_name == otherModulator.m_name && + this->m_frequencyActive == otherModulator.m_frequencyActive && + this->m_frequencyStandby == otherModulator.m_frequencyStandby); +} + +/** + * Equal operator != + */ +template bool CModulator::operator !=(const CModulator &otherModulator) const +{ + return !(otherModulator == (*this)); +} + + +// see here for the reason of thess forward instantiations +// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html +template class CModulator; + +} // namespace diff --git a/src/blackmisc/aviomodulator.h b/src/blackmisc/aviomodulator.h new file mode 100644 index 000000000..9275b7ee4 --- /dev/null +++ b/src/blackmisc/aviomodulator.h @@ -0,0 +1,167 @@ +#ifndef AVIOMODULATORUNIT_H +#define AVIOMODULATORUNIT_H +#include "blackmisc/aviobase.h" + +namespace BlackMisc { + +/*! + * \brief Base class for COM, NAV, Squawk units. + */ +template class CModulator : public CAvionicsBase +{ +private: + CFrequency m_frequencyActive; //!< active frequency + CFrequency m_frequencyStandby; //!< standby frequency + QString m_name; //!< name of the unit + +protected: + int m_digits; //!< digits used + + /*! + * \brief Default constructor + */ + CModulator() {} + /*! + * \brief Copy constructor + * \param otherUnit + */ + CModulator(const CModulator &otherUnit) : + m_frequencyActive(otherUnit.m_frequencyActive), m_frequencyStandby(otherUnit.m_frequencyStandby), + m_name(otherUnit.m_name), m_digits(otherUnit.m_digits) {} + /*! + * \brief Constructor + * \param name + * \param activeFrequency + * \param standbyFrequency + */ + CModulator(const QString &name, const CFrequency &activeFrequency, const CFrequency &standbyFrequency, int digits) : + m_name(name), m_frequencyActive(activeFrequency), + m_digits(digits), m_frequencyStandby(standbyFrequency) {} + /*! + * \brief Meaningful string representation + * \return + */ + virtual QString stringForStreamingOperator() const; + /*! + * \brief Set active frequency + * \param frequencyKHz + */ + void setFrequencyActiveKHz(double frequencyKHz) { this->m_frequencyActive = CFrequency(frequencyKHz, CFrequencyUnit::kHz()); } + /*! + * \brief Set standby frequency + * \param frequencyKHz + */ + void setFrequencyStandbyKHz(double frequencyKHz) { this->m_frequencyStandby = CFrequency(frequencyKHz, CFrequencyUnit::kHz()); } + /*! + * \brief Set active frequency + * \param frequencyMHz + */ + void setFrequencyActiveMHz(double frequencyMHz) { this->m_frequencyActive = CFrequency(frequencyMHz, CFrequencyUnit::MHz()); } + /*! + * \brief Set standby frequency + * \param frequencyMHz + */ + void setFrequencyStandbyMHz(double frequencyMHz) { this->m_frequencyStandby = CFrequency(frequencyMHz, CFrequencyUnit::MHz()); } + /*! + * \brief Assigment operator = + * \param otherModulator + * \return + */ + CModulator& operator =(const CModulator &otherModulator); + /*! + * \brief operator == + * \param otherModulator + * \return + */ + bool operator ==(const CModulator &otherModulator) const; + /*! + * \brief operator != + * \param otherModulator + * \return + */ + bool operator !=(const CModulator &otherModulator) const; + /*! + * \brief COM1 + * \return + */ + static const QString& NameCom1() { static QString n("COM1"); return n; } + /*! + * \brief COM2 + * \return + */ + static const QString& NameCom2() { static QString n("COM2"); return n; } + /*! + * \brief COM3 + * \return + */ + static const QString& NameCom3() { static QString n("COM3"); return n; } + /*! + * \brief NAV1 + * \return + */ + static const QString& NameNav1() { static QString n("NAV1"); return n; } + /*! + * \brief NAV2 + * \return + */ + static const QString& NameNav2() { static QString n("NAV2"); return n; } + /*! + * \brief NAV2 + * \return + */ + static const QString& NameNav3() { static QString n("NAV2"); return n; } + /*! + * \brief ADF1 + * \return + */ + static const QString& NameAdf1() { static QString n("ADF1"); return n; } + /*! + * \brief ADF2 + * \return + */ + static const QString& NameAdf2() { static QString n("ADF2"); return n; } + /*! + * \brief Frequency not set + * \return + */ + static const CFrequency& FrequencyNotSet() { static CFrequency f; return f; } + +public: + /*! + * \brief Virtual destructor + */ + virtual ~CModulator() {} + /*! + * \brief Toggle active and standby frequencies + */ + void toggleActiveStandby(); + /*! + * \brief Name + * \return + */ + QString getName() const { return this->m_name; } + /*! + * \brief Active frequency + * \return + */ + CFrequency getFrequencyActive() const { return this->m_frequencyActive; } + /*! + * \brief Standby frequency + * \return + */ + CFrequency getFrequencyStandby() const { return this->m_frequencyActive; } + /*! + * \brief Set active frequency + * \param frequency + */ + void setFrequencyActive(const CFrequency &frequency) { this->m_frequencyActive = frequency; } + /*! + * \brief Set standby frequency + * \param frequency + */ + void setFrequencyStandby(const CFrequency &frequency) { this->m_frequencyStandby = frequency; } +}; + +} // namespace + +#endif // AVIOMODULATORUNIT_H diff --git a/src/blackmisc/avionbase.cpp b/src/blackmisc/avionbase.cpp new file mode 100644 index 000000000..5d2bebe61 --- /dev/null +++ b/src/blackmisc/avionbase.cpp @@ -0,0 +1,12 @@ +#include "aviobase.h" + +namespace BlackMisc { + +/** + * Defaultc + */ +CAvionicsBase::CAvionicsBase() +{ +} + +} // namespace diff --git a/src/blackmisc/blackmisc.pro b/src/blackmisc/blackmisc.pro index 031b03570..5726d3799 100644 --- a/src/blackmisc/blackmisc.pro +++ b/src/blackmisc/blackmisc.pro @@ -52,7 +52,10 @@ HEADERS += \ avheading.h \ avtrack.h \ avaltitude.h \ - avverticalpositions.h + avverticalpositions.h \ + aviobase.h \ + aviomodulator.h \ + aviocomsystem.h SOURCES += \ logmessage.cpp \ @@ -79,6 +82,7 @@ SOURCES += \ avheading.cpp \ avtrack.cpp \ avaltitude.cpp \ - avverticalpositions.cpp + avverticalpositions.cpp \ + aviomodulator.cpp DESTDIR = ../../lib diff --git a/src/blackmisc/pqbase.cpp b/src/blackmisc/pqbase.cpp index e3c0e1689..09a216d71 100644 --- a/src/blackmisc/pqbase.cpp +++ b/src/blackmisc/pqbase.cpp @@ -94,9 +94,12 @@ 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): - 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) +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_displayDigits(displayDigits), + m_conversionFactorToSIConversionUnit(conversionFactorToSI), + m_epsilon(epsilon), m_multiplier(multiplier), m_fromSiConverter(fromSiConverter), m_toSiConverter(toSiConverter) { // void } @@ -105,9 +108,9 @@ CMeasurementUnit::CMeasurementUnit(const QString &name, const QString &unitName, * Copy constructor */ CMeasurementUnit::CMeasurementUnit(const CMeasurementUnit &otherUnit): - 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) + 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), m_fromSiConverter(otherUnit.m_fromSiConverter), m_toSiConverter(otherUnit.m_toSiConverter) { // void } @@ -121,12 +124,14 @@ CMeasurementUnit &CMeasurementUnit::operator =(const CMeasurementUnit &otherUnit 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_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; + this->m_fromSiConverter = otherUnit.m_fromSiConverter; + this->m_toSiConverter = otherUnit.m_toSiConverter; return *this; } @@ -138,7 +143,7 @@ bool CMeasurementUnit::operator ==(const CMeasurementUnit &otherUnit) const if ( this == &otherUnit ) return true; 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; + && this->m_isSiUnit==otherUnit.m_isSiUnit; } /** diff --git a/src/blackmisc/pqbase.h b/src/blackmisc/pqbase.h index 75ad05c34..48f85c8c6 100644 --- a/src/blackmisc/pqbase.h +++ b/src/blackmisc/pqbase.h @@ -162,6 +162,7 @@ public: * Base class for all units, such as meter, hertz. */ class CMeasurementUnit { + /*! * \brief Stream << overload to be used in debugging messages * \param d @@ -179,18 +180,27 @@ class CMeasurementUnit { */ friend CLogMessage operator<<(CLogMessage log, const CMeasurementUnit &unit); +protected: + /*! + * Points to a individual converter method + */ + typedef double(*UnitConverter)(const CMeasurementUnit&, double); + 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? + 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 for string conversions CMeasurementPrefix m_multiplier; //!< multiplier (kilo, Mega) + UnitConverter m_toSiConverter; + UnitConverter m_fromSiConverter; protected: + /*! * Constructor by parameter * \param name @@ -202,7 +212,9 @@ protected: * \param displayDigits * \param epsilon */ - CMeasurementUnit(const QString &name, const QString &unitName, const QString &type, bool isSiUnit, bool isSiBaseUnit, double conversionFactorToSI = 1, const CMeasurementPrefix &multiplier = CMeasurementPrefix::None(), qint32 displayDigits = 2, double epsilon = 1E-10); + 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 = nullptr, UnitConverter fromSiConverter = nullptr); /*! * \brief Copy constructor * \param otherUnit @@ -220,6 +232,20 @@ protected: * \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 implementaion is simply factor based. + * \param value + * \return + */ + virtual double conversionFromSiConversionUnit(double value) const { return value / this->m_conversionFactorToSIConversionUnit; } public: /*! @@ -238,17 +264,17 @@ public: * \brief Representing an SI unit? Examples: kilometer, meter, hertz * \return */ - bool isSiUnit() const { return this->m_isSIUnit;} + bool isSiUnit() const { return this->m_isSiUnit;} /*! * \brief Representing an base SI unit? Examples: second, meter * \return */ - bool isSiBaseUnit() const { return this->m_isSIUnit;} + 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; } + bool isUnprefixedSiUnit() const { return this->m_isSiUnit && this->m_multiplier.getFactor() == 1; } /*! * \brief Name such as "meter" * \return @@ -264,20 +290,21 @@ public: * \return */ QString getType() const { return this->m_type; } + /*! * Given value to conversion SI conversion unit (e.g. meter, hertz). - * Standard implementaion is simply factor based. + * Standard implementation is simply factor based. * \param value * \return */ - virtual double convertToSiConversionUnit(double value) const { return value * this->m_conversionFactorToSIConversionUnit; } + double convertToSiConversionUnit(double value) const { return (this->m_toSiConverter) ? this->m_toSiConverter((*this), value) : this->conversionToSiConversionUnit(value); } /*! - * \brief Value from SI conversion unit to this unit. - * Standard implementaion is simply factor based. + * Value from SI conversion unit to this unit. + * Standard implementation is simply factor based. * \param value * \return */ - virtual double convertFromSiConversionUnit(double value) const { return value / this->m_conversionFactorToSIConversionUnit; } + double convertFromSiConversionUnit(double value) const { return (this->m_fromSiConverter) ? this->m_fromSiConverter((*this), value) : this->conversionFromSiConversionUnit(value); } /*! * Rounded string utility method, virtual so units can have * specialized formatting diff --git a/src/blackmisc/pqconstants.h b/src/blackmisc/pqconstants.h index 62ef417d4..f381ec43a 100644 --- a/src/blackmisc/pqconstants.h +++ b/src/blackmisc/pqconstants.h @@ -39,6 +39,21 @@ public: * \return */ static const CLength& Length0ft() { static CLength l(0, CLengthUnit::ft()); return l;} + /*! + * \brief Unicom frequency + * \return + */ + static const CFrequency& FrequencyUnicom() { static CFrequency f(122.8, CFrequencyUnit::MHz()); return f;} + /*! + * \brief Civil aircraft emergency frequency + * \return + */ + static const CFrequency& FrequencyInternationalAirDistress() { static CFrequency f(121.5, CFrequencyUnit::MHz()); return f;} + /*! + * \brief Military aircraft emergency frequency + * \return + */ + static const CFrequency& FrequencyMilitaryAirDistress() { static CFrequency f(243.0, CFrequencyUnit::MHz()); return f;} }; } // namespace #endif // PQCONSTANTS_H diff --git a/src/blackmisc/pqphysicalquantity.cpp b/src/blackmisc/pqphysicalquantity.cpp index 77edb80b6..395136852 100644 --- a/src/blackmisc/pqphysicalquantity.cpp +++ b/src/blackmisc/pqphysicalquantity.cpp @@ -364,7 +364,7 @@ template double CPhysicalQuantity::convertedSiValueT } -// see here for the reason of this forward instants +// see here for the reason of thess forward instantiations // http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html template class CPhysicalQuantity; template class CPhysicalQuantity; diff --git a/src/blackmisc/pqunits.cpp b/src/blackmisc/pqunits.cpp index e91401710..936ba1c33 100644 --- a/src/blackmisc/pqunits.cpp +++ b/src/blackmisc/pqunits.cpp @@ -5,7 +5,7 @@ namespace BlackMisc { /** * Convert to SI */ -double CTemperatureUnit::convertToSiConversionUnit(double value) const +double CTemperatureUnit::conversionToSiConversionUnit(double value) const { double v = value + this->m_conversionOffsetToSi; v *= this->getConversionFactorToSI(); @@ -15,7 +15,7 @@ double CTemperatureUnit::convertToSiConversionUnit(double value) const /** * Convert from SI */ -double CTemperatureUnit::convertFromSiConversionUnit(double value) const +double CTemperatureUnit::conversionFromSiConversionUnit(double value) const { double v = value / this->getConversionFactorToSI(); v -= this->m_conversionOffsetToSi; @@ -25,49 +25,34 @@ double CTemperatureUnit::convertFromSiConversionUnit(double value) const /** * Convert from SI */ -double CAngleUnit::convertFromSiConversionUnit(double value) const +double CAngleUnit::conversionSexagesimalFromSi(const CMeasurementUnit &angleUnit, double value) { - 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()) { - // using rounding here, since fractions can lead to ugly sexagesimal conversion - // e.g. 185.499999 gives 185 29' 59.9999" - value = this->epsilonRounding(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); - } + // using rounding here, since fractions can lead to ugly sexagesimal conversion + // e.g. 185.499999 gives 185 29' 59.9999" + value = angleUnit.epsilonRounding(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::convertToSiConversionUnit(double value) const +double CAngleUnit::conversionSexagesimalToSi(const CMeasurementUnit &, double value) { - // 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; + 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; } /** @@ -90,4 +75,4 @@ QString CAngleUnit::toQStringRounded(double value, int digits) const return s; } -} +} // namespace diff --git a/src/blackmisc/pqunits.h b/src/blackmisc/pqunits.h index 3929db710..12570f34d 100644 --- a/src/blackmisc/pqunits.h +++ b/src/blackmisc/pqunits.h @@ -65,7 +65,7 @@ public: /*! * Specialized class for angles (degrees, radian). - * \author KWB + * \author KWB, MS */ class CAngleUnit : public CMeasurementUnit { private: @@ -79,29 +79,33 @@ private: * \param displayDigits * \param epsilon */ - CAngleUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : - CMeasurementUnit(name, unitName, "angle", isSIUnit, false, conversionFactorToSI, mulitplier, displayDigits, epsilon) + CAngleUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, + const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, + double epsilon = 1E-9, UnitConverter converterToSi = nullptr, UnitConverter converterFromSi= nullptr) : + CMeasurementUnit(name, unitName, "angle", isSIUnit, false, conversionFactorToSI, + mulitplier, displayDigits, epsilon, converterToSi, converterFromSi) { // void } + /*! + * \brief Special conversion for sexagesimal degrees + * \param value + * \return + */ + static double conversionSexagesimalToSi(const CMeasurementUnit &angleUnit, double value); + /*! + * \brief Special conversion for sexagesimal degrees + * \param value + * \return + */ + static double conversionSexagesimalFromSi(const CMeasurementUnit &angleUnit, double value); + public: /*! * \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 @@ -123,12 +127,13 @@ public: * \brief Sexagesimal degree (degree, minute, seconds) * \return */ - static const CAngleUnit& sexagesimalDeg() { static CAngleUnit deg("segadecimal degree", "°", false, M_PI/180); return deg;} + static const CAngleUnit& sexagesimalDeg() { static CAngleUnit deg("segadecimal degree", "°", false, M_PI/180, + CMeasurementPrefix::One(),0, 1E-9, CAngleUnit::conversionSexagesimalToSi, CAngleUnit::conversionSexagesimalFromSi); return deg;} }; /*! * Specialized class for frequency (hertz, mega hertz, kilo hertz). - * \author KWB + * \author KWB, MS */ class CFrequencyUnit : public CMeasurementUnit { private: @@ -159,22 +164,22 @@ public: * \brief Kilohertz * \return */ - static const CFrequencyUnit& kHz() { static CFrequencyUnit kHz("kilohertz", "kHz", true, CMeasurementPrefix::k().getFactor(), CMeasurementPrefix::k(), 0);return kHz;} + static const CFrequencyUnit& kHz() { static CFrequencyUnit kHz("kilohertz", "kHz", true, CMeasurementPrefix::k().getFactor(), CMeasurementPrefix::k(), 1);return kHz;} /*! * \brief Megahertz * \return */ - static const CFrequencyUnit& MHz() { static CFrequencyUnit MHz("megahertz", "MHz", false, CMeasurementPrefix::M().getFactor(), CMeasurementPrefix::M(), 0); return MHz;} + static const CFrequencyUnit& MHz() { static CFrequencyUnit MHz("megahertz", "MHz", false, CMeasurementPrefix::M().getFactor(), CMeasurementPrefix::M(), 2); return MHz;} /*! * \brief Gigahertz * \return */ - static const CFrequencyUnit& GHz() { static CFrequencyUnit GHz("gigahertz", "GHz", true, CMeasurementPrefix::G().getFactor(), CMeasurementPrefix::G(), 0);return GHz;} + static const CFrequencyUnit& GHz() { static CFrequencyUnit GHz("gigahertz", "GHz", true, CMeasurementPrefix::G().getFactor(), CMeasurementPrefix::G(), 2);return GHz;} }; /*! * Specialized class for mass units (kg, lbs). - * \author KWB + * \author KWB, MS */ class CMassUnit : public CMeasurementUnit { private: @@ -220,7 +225,7 @@ public: /*! * Specialized class for pressure (psi, hPa, bar). - * \author KWB + * \author KWB, MS */ class CPressureUnit : public CMeasurementUnit { private: @@ -238,6 +243,10 @@ private: CPressureUnit(const QString &name, const QString &unitName, bool isSIUnit, double conversionFactorToSI = 1.0, const CMeasurementPrefix &mulitplier = CMeasurementPrefix::One(), qint32 displayDigits = 2, double epsilon = 1E-9) : CMeasurementUnit(name, unitName, "frequency", isSIUnit, false, conversionFactorToSI, mulitplier, displayDigits, epsilon) {} public: + /*! + * \brief Copy constructor + * \param otherUnit + */ CPressureUnit(const CPressureUnit &otherUnit) : CMeasurementUnit(otherUnit) { // void @@ -301,6 +310,19 @@ private: */ 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) {} +protected: + /*! + * \brief Convert to SI conversion unit, specific for temperature + * \param value + * \return + */ + virtual double CTemperatureUnit::conversionToSiConversionUnit(double value) const; + /*! + * \brief Convert from SI conversion unit, specific for temperature + * \param value + * \return + */ + virtual double CTemperatureUnit::conversionFromSiConversionUnit(double value) const; public: /*! * \brief Copy constructor @@ -317,18 +339,6 @@ public: 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 @@ -344,7 +354,6 @@ public: * \return */ static const CTemperatureUnit& F() { static CTemperatureUnit F("Fahrenheit", "°F", false, false, 5.0/9.0, 459.67);return F;} - }; /*! diff --git a/tests/blackmisc/testaviationbase.cpp b/tests/blackmisc/testaviationbase.cpp index 351f0d751..437e46bd2 100644 --- a/tests/blackmisc/testaviationbase.cpp +++ b/tests/blackmisc/testaviationbase.cpp @@ -44,4 +44,16 @@ void CTestAviationBase::verticalPosition() QVERIFY2(vp1== vp2, "Values shall be equal"); } +/** + * COM and NAV units + */ +void CTestAviationBase::comAndNav() +{ + CComSystem c1 = CComSystem::getCom1Unit(122.8); + CComSystem c2 = CComSystem::getCom2Unit(122.8); + QVERIFY2(c1 != c2, "COM units shall not be equal"); + c1 = c2; + QVERIFY2(c1 == c2, "COM units shall be equal"); +} + } // namespace diff --git a/tests/blackmisc/testaviationbase.h b/tests/blackmisc/testaviationbase.h index ca42b04b9..51b9cda28 100644 --- a/tests/blackmisc/testaviationbase.h +++ b/tests/blackmisc/testaviationbase.h @@ -5,6 +5,8 @@ #include "blackmisc/pqconstants.h" #include "blackmisc/avheading.h" #include "blackmisc/avverticalpositions.h" +#include "blackmisc/aviocomsystem.h" + using namespace BlackMisc; namespace BlackMiscTest { @@ -34,6 +36,11 @@ private slots: */ void verticalPosition(); + /*! + * \brief COM and NAV units + */ + void comAndNav(); + }; } // namespace