mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
417 lines
12 KiB
C++
417 lines
12 KiB
C++
/* Copyright (C) 2013 VATSIM Community / contributors
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "blackmisc/pqallquantities.h"
|
|
|
|
namespace BlackMisc
|
|
{
|
|
namespace PhysicalQuantities
|
|
{
|
|
|
|
/*
|
|
* Constructor by integer
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
this->setUnitValue(baseValue);
|
|
}
|
|
|
|
/*
|
|
* Copy constructor
|
|
*/
|
|
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)
|
|
{
|
|
// void
|
|
}
|
|
|
|
/*
|
|
* Destructor
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>::~CPhysicalQuantity()
|
|
{
|
|
// void
|
|
}
|
|
|
|
/*
|
|
* Equal operator ==
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator ==(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if (this == &otherQuantity) return true;
|
|
if (this->m_unit.getType() != otherQuantity.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 == otherQuantity.m_unit)
|
|
{
|
|
// same unit
|
|
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
|
|
{
|
|
// pure integer comparison, no rounding issues
|
|
eq = this->m_unitValueI == otherQuantity.m_unitValueI;
|
|
}
|
|
else
|
|
{
|
|
// same unit, comparison based on double
|
|
diff = qAbs(this->m_unitValueD - otherQuantity.m_unitValueD);
|
|
eq = diff <= (lenient * this->m_unit.getEpsilon());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// based on SI value
|
|
diff = qAbs(this->m_convertedSiUnitValueD - otherQuantity.m_convertedSiUnitValueD);
|
|
eq = diff <= (lenient * this->m_conversionSiUnit.getEpsilon());
|
|
}
|
|
return eq;
|
|
}
|
|
|
|
/*
|
|
* Not equal
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator !=(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if (this == &otherQuantity) return false;
|
|
return !((*this) == otherQuantity);
|
|
}
|
|
|
|
/*
|
|
* Assignment operator =
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ>& CPhysicalQuantity<MU, PQ>::operator=(const CPhysicalQuantity<MU, PQ> &otherQuantity)
|
|
{
|
|
|
|
// Check for self-assignment!
|
|
if (this == &otherQuantity) return *this; // Same object?
|
|
|
|
this->m_unitValueI = otherQuantity.m_unitValueI;
|
|
this->m_unitValueD = otherQuantity.m_unitValueD;
|
|
this->m_convertedSiUnitValueD = otherQuantity.m_convertedSiUnitValueD;
|
|
this->m_isIntegerBaseValue = otherQuantity.m_isIntegerBaseValue;
|
|
this->m_unit = otherQuantity.m_unit;
|
|
this->m_conversionSiUnit = otherQuantity.m_conversionSiUnit;
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Plus operator
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator +=(const CPhysicalQuantity<MU, PQ> &otherQuantity)
|
|
{
|
|
if (this->m_unit == otherQuantity.m_unit)
|
|
{
|
|
// same unit
|
|
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
|
|
{
|
|
// pure integer, no rounding issues
|
|
this->setUnitValue(otherQuantity.m_unitValueI + this->m_unitValueI);
|
|
}
|
|
else
|
|
{
|
|
this->setUnitValue(otherQuantity.m_unitValueD + this->m_unitValueD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double v = otherQuantity.value(this->m_unit);
|
|
this->setUnitValue(v + this->m_unitValueD);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Plus operator
|
|
*/
|
|
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator +(const PQ &otherQuantity) const
|
|
{
|
|
PQ plus(otherQuantity);
|
|
plus += (*this);
|
|
return plus;
|
|
}
|
|
|
|
|
|
/*
|
|
* Explicit plus
|
|
*/
|
|
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::addUnitValue(double value)
|
|
{
|
|
this->setUnitValue(this->m_unitValueD + value);
|
|
}
|
|
|
|
/*
|
|
* Explicit minus
|
|
*/
|
|
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::substractUnitValue(double value)
|
|
{
|
|
this->setUnitValue(this->m_unitValueD - value);
|
|
}
|
|
|
|
/*
|
|
* Minus operator
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator -=(const CPhysicalQuantity<MU, PQ> &otherQuantity)
|
|
{
|
|
if (this->m_unit == otherQuantity.m_unit)
|
|
{
|
|
// same unit
|
|
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
|
|
{
|
|
// pure integer, no rounding issues
|
|
this->setUnitValue(otherQuantity.m_unitValueI - this->m_unitValueI);
|
|
}
|
|
else
|
|
{
|
|
this->setUnitValue(otherQuantity.m_unitValueD - this->m_unitValueD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double v = otherQuantity.value(this->m_unit);
|
|
this->setUnitValue(v - this->m_unitValueD);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Minus operator
|
|
*/
|
|
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator -(const PQ &otherQuantity) const
|
|
{
|
|
PQ minus = *derived();
|
|
minus -= otherQuantity;
|
|
return minus;
|
|
}
|
|
|
|
/*
|
|
* Multiply operator
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator *=(double multiply)
|
|
{
|
|
this->setUnitValue(this->m_unitValueD * multiply);
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Multiply operator
|
|
*/
|
|
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator *(double multiply) const
|
|
{
|
|
PQ times = *derived();
|
|
times *= multiply;
|
|
return times;
|
|
}
|
|
|
|
/*
|
|
* Divide operator /=
|
|
*/
|
|
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator /=(double divide)
|
|
{
|
|
this->setUnitValue(this->m_unitValueD / divide);
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Divide operator /
|
|
*/
|
|
template <class MU, class PQ> PQ CPhysicalQuantity<MU, PQ>::operator /(double divide) const
|
|
{
|
|
PQ div = *derived();
|
|
div /= divide;
|
|
return div;
|
|
}
|
|
|
|
/*
|
|
* Less operator <
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator <(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if ((*this) == otherQuantity) return false;
|
|
|
|
// == considers epsilon, so we now have a diff > epsilon here
|
|
double diff = this->m_convertedSiUnitValueD - otherQuantity.m_convertedSiUnitValueD;
|
|
return (diff < 0);
|
|
}
|
|
|
|
/*
|
|
* Greater than
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator >(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if (this == &otherQuantity) return false;
|
|
return otherQuantity < (*this);
|
|
}
|
|
|
|
/*
|
|
* Greater / Equal
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator >=(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if (this == &otherQuantity) return true;
|
|
return !(*this < otherQuantity);
|
|
}
|
|
|
|
/*
|
|
* Less equal
|
|
*/
|
|
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator <=(const CPhysicalQuantity<MU, PQ> &otherQuantity) const
|
|
{
|
|
if (this == &otherQuantity) return true;
|
|
return !(*this > otherQuantity);
|
|
}
|
|
|
|
/*
|
|
* Switch to another unit
|
|
*/
|
|
template <class MU, class PQ> PQ &CPhysicalQuantity<MU, PQ>::switchUnit(const MU &newUnit)
|
|
{
|
|
if (this->m_unit != newUnit)
|
|
{
|
|
double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit);
|
|
this->m_unit = newUnit;
|
|
this->setUnitValue(cf);
|
|
}
|
|
return *derived();
|
|
}
|
|
|
|
/*
|
|
* Init by integer
|
|
*/
|
|
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::setUnitValue(qint32 baseValue)
|
|
{
|
|
this->m_unitValueI = baseValue;
|
|
this->m_unitValueD = double(baseValue);
|
|
this->m_isIntegerBaseValue = true;
|
|
this->setConversionSiUnitValue();
|
|
}
|
|
|
|
/*
|
|
* Init by double
|
|
*/
|
|
template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::setUnitValue(double baseValue)
|
|
{
|
|
this->m_unitValueD = baseValue;
|
|
this->m_unitValueI = qRound(baseValue);
|
|
this->m_isIntegerBaseValue = false;
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Value rounded in unit
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Value rounded in unit
|
|
*/
|
|
template <class MU, class PQ> double CPhysicalQuantity<MU, PQ>::valueRounded(const MU &unit, int digits) const
|
|
{
|
|
return unit.valueRounded(this->value(unit), digits);
|
|
}
|
|
|
|
/*
|
|
* Value in unit
|
|
*/
|
|
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);
|
|
}
|
|
|
|
|
|
// 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<CLengthUnit, CLength>;
|
|
template class CPhysicalQuantity<CPressureUnit, CPressure>;
|
|
template class CPhysicalQuantity<CFrequencyUnit, CFrequency>;
|
|
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>;
|
|
template class CPhysicalQuantity<CAccelerationUnit, CAcceleration>;
|
|
|
|
} // namespace
|
|
} // namespace
|