Further details on classes like epsilon compare, further unit tests.

This commit is contained in:
Klaus Basan
2013-04-24 01:59:17 +02:00
parent bd53371de4
commit 472521f281
17 changed files with 187 additions and 70 deletions

View File

@@ -75,8 +75,9 @@ public:
/*!
* \brief Cast as QString
* \remarks operator cast caused too many ambiguity trouble
*/
operator QString() const
QString toQString() const
{
return this->stringForConverter();
}

View File

@@ -66,7 +66,7 @@ CCoordinateEcef CCoordinateTransformation::toEcef(const CCoordinateNed &ned)
*/
CCoordinateEcef CCoordinateTransformation::toEcef(const CCoordinateGeodetic &geo)
{
// TODO: Clarify the comparions with fixed angles (==90, ==180) -> what happens here
// TODO: Clarify the comparisons with fixed angles (==90, ==180) -> what happens here
CLatitude lat = geo.latitude();
CLongitude lon = geo.longitude();

View File

@@ -34,5 +34,33 @@ qreal CMath::cubicRootReal(qreal x)
return x < 0 ? -result : result;
}
/*
* Round utility method
*/
double CMath::round(double value, int digits)
{
// gosh, is there no Qt method for this??? It's year 2013
double fractpart, intpart;
fractpart = modf(value, &intpart);
if (fractpart == 0) return value; // do not mess any "integers" to the worse
double m = pow(10.0, digits);
qint64 ri = qRound(value * m); // do not loose any range here
double rv = double(ri) / m;
return rv;
}
/*
* Round by given epsilon value
*/
double CMath::roundEpsilon(double value, double epsilon)
{
double fractpart, intpart;
fractpart = modf(value, &intpart);
if (fractpart == 0) return value; // do not mess any "integers" to the worse
qint64 ri = qRound(value / epsilon);
double rv = double(ri) * epsilon; // do not loose any range here
return rv;
}
} // namespace
} // namespace

View File

@@ -15,10 +15,10 @@ namespace Math
// Some namespace wide constant values
//! Mathematical constant Pi
const qreal PI = 4.0 * qAtan(1.0);
const double PI = 4.0 * qAtan(1.0);
//! 2 * Pi
const qreal TwoPI = 2.0 * PI;
const double TwoPI = 2.0 * PI;
/*!
* \brief Math utils
@@ -33,14 +33,14 @@ public:
* \param y
* \return
*/
static qreal hypot(qreal x, qreal y);
static double hypot(double x, double y);
/*!
* \brief Calculates the square of x
* \param x
* \return
*/
static inline qreal square(qreal x)
static inline double square(double x)
{
return x * x;
}
@@ -50,7 +50,7 @@ public:
* \param x
* \return
*/
static inline qreal cubic(const qreal x)
static inline double cubic(const double x)
{
return x * x * x;
}
@@ -60,7 +60,23 @@ public:
* \param x
* \return
*/
static qreal cubicRootReal(qreal x);
static double cubicRootReal(double x);
/*!
* \brief Utility round method
* \param value
* \param digits
* \return
*/
static double round(double value, int digits);
/*!
* \brief Round by given epsilon, e.g.
* \param value
* \param epsilon
* \return
*/
static double roundEpsilon(double value, double epsilon);
private:
/*!

View File

@@ -69,11 +69,11 @@ template<class ImplMatrix, int Rows, int Columns> bool CMatrixBase<ImplMatrix, R
}
/*
* All values zero?
* All values equal?
*/
template<class ImplMatrix, int Rows, int Columns> bool CMatrixBase<ImplMatrix, Rows, Columns>::allValuesEqual() const
{
double v = this->getElement(0,0);
double v = this->getElement(0, 0);
for (int r = 0; r < Rows; r++)
{
for (int c = 0; c < Columns; c++)
@@ -84,6 +84,19 @@ template<class ImplMatrix, int Rows, int Columns> bool CMatrixBase<ImplMatrix, R
return true;
}
/*
* Round all values
*/
template<class ImplMatrix, int Rows, int Columns> void CMatrixBase<ImplMatrix, Rows, Columns>::round()
{
for (int r = 0; r < Rows; r++)
{
for (int c = 0; c < Columns; c++)
{
this->m_matrix(r, c) = CMath::roundEpsilon(this->m_matrix(r, c), 1E-10);
}
}
}
/*
* Convert to string

View File

@@ -203,6 +203,18 @@ public:
return this->m_matrix.isIdentity();
}
/*!
* \brief Is identity matrix? Epsilon considered.
* \return
*/
bool isIdentityEpsilon() const
{
ImplMatrix m(0.0);
m += (*this);
m.round();
return m.isIdentity();
}
/*!
* \brief Set as identity matrix
* \return
@@ -228,6 +240,18 @@ public:
*/
bool isZero() const;
/*!
* \brief Is identity matrix? Epsilon considered.
* \return
*/
bool isZeroEpsilon() const
{
ImplMatrix m(0.0);
m += (*this);
m.round();
return m.isZero();
}
/*!
* \brief All values equal, if so matirx is not invertible
* \return
@@ -240,6 +264,11 @@ public:
*/
void fill(double value) { this->m_matrix.fill(value); }
/*!
* \brief Round all values
*/
void round();
/*!
* \brief Get element
* \param row

View File

@@ -92,13 +92,13 @@ template <class ImplClass> void CVector3DBase<ImplClass>::setElement(size_t row,
}
/*
* Corss product
* Cross product
*/
template <class ImplClass> ImplClass CVector3DBase<ImplClass>::crossProduct(const ImplClass &otherVector) const
{
ImplClass v(otherVector);
v.m_i = this->m_j * otherVector.m_k - this->m_k * otherVector.m_j;
v.m_j = this->m_k * otherVector.m_i - this->m_j * otherVector.m_k;
v.m_j = this->m_k * otherVector.m_i - this->m_i * otherVector.m_k;
v.m_k = this->m_i * otherVector.m_j - this->m_j * otherVector.m_i;
return v;
}

View File

@@ -7,6 +7,7 @@
#define BLACKMISC_MATHVECTOR3DBASE_H
#include "blackmisc/basestreamstringifier.h"
#include "blackmisc/mathematics.h"
namespace BlackMisc
{
@@ -75,6 +76,26 @@ public:
*/
void setZero();
/*!
* \brief Set zeros
*/
bool isZero() const
{
return this->m_i == 0 && this->m_j == 0 && this->m_k == 0;
}
/*!
* \brief Is identity matrix? Epsilon considered.
* \return
*/
bool isZeroEpsilon() const
{
ImplClass v;
v += (*this);
v.round();
return v.isZero();
}
/*!
* \brief Set zeros
*/
@@ -370,6 +391,18 @@ public:
{
return sqrt(this->lengthSquared());
}
/*!
* \brief Round this vector
*/
void round()
{
const double epsilon = 1E-10;
this->m_i = BlackMisc::Math::CMath::roundEpsilon(this->m_i, epsilon);
this->m_j = BlackMisc::Math::CMath::roundEpsilon(this->m_j, epsilon);
this->m_k = BlackMisc::Math::CMath::roundEpsilon(this->m_k, epsilon);
}
};
} // namespace

View File

@@ -6,6 +6,7 @@
#ifndef BLACKMISC_PQANGLE_H
#define BLACKMISC_PQANGLE_H
#include "blackmisc/pqphysicalquantity.h"
#include "blackmisc/mathematics.h"
namespace BlackMisc
{
@@ -46,15 +47,17 @@ public:
* \brief Convenience method PI
* \return
*/
const static double pi() {
const static double pi()
{
return M_PI;
}
/*!
* \brief Value as factor of PI (e.g. 0.5PI)
* \return
*/
double piFactor() const {
return CMeasurementUnit::round(this->convertedSiValueToDouble() / M_PI, 6);
double piFactor() const
{
return BlackMisc::Math::CMath::round(this->convertedSiValueToDouble() / M_PI, 6);
}
};

View File

@@ -1,9 +1,12 @@
/* Copyright (C) 2013 VATSIM Community
/* 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/pqbase.h"
#include "blackmisc/mathematics.h"
using namespace BlackMisc::Math;
namespace BlackMisc
{
@@ -35,7 +38,7 @@ CMeasurementPrefix::CMeasurementPrefix(const CMeasurementPrefix &otherMultiplier
/*
* Assignment operator
*/
CMeasurementPrefix& CMeasurementPrefix::operator=(const CMeasurementPrefix &otherMultiplier)
CMeasurementPrefix &CMeasurementPrefix::operator=(const CMeasurementPrefix &otherMultiplier)
{
if (this == &otherMultiplier) return *this; // Same object? Yes, so skip assignment, and just return *this
@@ -170,7 +173,7 @@ QString CMeasurementUnit::valueRoundedWithUnit(double value, int digits) const
double CMeasurementUnit::valueRounded(double value, int digits) const
{
if (digits < 0) digits = this->m_displayDigits;
return CMeasurementUnit::round(value, digits);
return CMath::round(value, digits);
}
/*
@@ -179,30 +182,19 @@ double CMeasurementUnit::valueRounded(double value, int digits) const
QString CMeasurementUnit::toQStringRounded(double value, int digits) const
{
if (digits < 0) digits = this->m_displayDigits;
double v = CMeasurementUnit::round(value, digits);
double v = CMath::round(value, digits);
QString s = QLocale::system().toString(v, 'f', digits);
return s;
}
/*
* 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;
}
/*
* Epsilon rounding
*/
double CMeasurementUnit::epsilonRounding(double value) const
double CMeasurementUnit::epsilonUpRounding(double value) const
{
// does notwork reliable with qRound for some reason
double v = floor((value + this->m_epsilon) / this->m_epsilon);
// Rounds a little up in order to avoid fractions
double eps = value > 0 ? this->m_epsilon : -1.0 * this->m_epsilon;
double v = floor((value + eps) / this->m_epsilon);
v *= this->m_epsilon;
return v;
}

View File

@@ -93,10 +93,6 @@ public:
/*!
* \brief Cast as double
*/
operator double() const
{
return this->m_factor;
}
/*!
* \brief Factor, e.g.1000 for "kilo"
@@ -106,6 +102,16 @@ public:
{
return this->m_factor;
}
/*!
* \brief Factor
* \return
*/
double toDouble() const
{
return this->getFactor();
}
/*!
* \brief Name, e.g. "kilo"
* \return
@@ -114,6 +120,7 @@ public:
{
return this->m_name;
}
/*!
* \brief Prefix, e.g. "k" for "kilo"
* \return
@@ -464,25 +471,17 @@ public:
*/
double conversionToUnit(double value, const CMeasurementUnit &to) const;
// --------------------------------------------------------------------
// -- static
// --------------------------------------------------------------------
/*!
* \brief Utility round method
* \param value
* \param digits
* \return
*/
static double round(double value, int digits);
/*!
* Epsilon rounding. In some conversion rouding is required to avoid
* periodical numbers.
* \param value
* \return
*/
double epsilonRounding(double value) const;
double epsilonUpRounding(double value) const;
// --------------------------------------------------------------------
// -- static
// --------------------------------------------------------------------
/*!
* \brief Unit is not specified

View File

@@ -6,6 +6,7 @@
#ifndef BLACKMISC_PQPHYSICALQUANTITY_H
#define BLACKMISC_PQPHYSICALQUANTITY_H
#include "blackmisc/mathematics.h"
#include "blackmisc/pqbase.h"
#include "blackmisc/pqunits.h"
#include "blackmisc/debug.h"
@@ -217,7 +218,8 @@ public:
*/
qint32 convertedSiValueToInteger() const
{
return static_cast<qint32>(CMeasurementUnit::round(this->m_convertedSiUnitValueD, 0));
return static_cast<qint32>(
BlackMisc::Math::CMath::round(this->m_convertedSiUnitValueD, 0));
}
/*!
@@ -255,15 +257,7 @@ public:
*/
void substractUnitValue(double value);
/*!
* \brief Cast as QString
*/
operator QString() const
{
return this->unitValueRoundedWithUnit();
}
/*!
/*!
* \brief Multiply operator *=
* \param multiply
* \return

View File

@@ -37,7 +37,7 @@ double CAngleUnit::conversionSexagesimalFromSi(const CMeasurementUnit &angleUnit
{
// 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
value = angleUnit.epsilonUpRounding(value * 180 / M_PI); // degree
double v = floor(value);
double c = value - v;
double mr = c * 60.0;

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2013 VATSIM Community / authors
/* 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/. */
@@ -649,4 +649,4 @@ public:
} // namespace
} // namespace
#endif // BLACKMISC_PQUNITS_H
#endif // guard