Initial structure for refactoring, some conversions still missing. Especially required further test cases.

This commit is contained in:
Klaus Basan
2013-04-19 00:19:41 +02:00
parent 5bf308c54b
commit 8121babe77
22 changed files with 607 additions and 120 deletions

View File

@@ -46,6 +46,10 @@ int CSamplesPhysicalQuantities::samples()
l3 *= 1.5;// 3km now l3 *= 1.5;// 3km now
qDebug() << l2 << l3; qDebug() << l2 << l3;
l3 = l3 * 2;
qDebug() << "doubled l3:" << l3;
CFrequency f1(1E6, CFrequencyUnit::Hz()); // 1MHz CFrequency f1(1E6, CFrequencyUnit::Hz()); // 1MHz
qDebug() << f1 << f1.valueRoundedWithUnit(CFrequencyUnit::MHz()) << f1.valueRoundedWithUnit(CFrequencyUnit::GHz(), 3); qDebug() << f1 << f1.valueRoundedWithUnit(CFrequencyUnit::MHz()) << f1.valueRoundedWithUnit(CFrequencyUnit::GHz(), 3);

View File

@@ -11,15 +11,15 @@ namespace BlackMiscTest
*/ */
int CSamplesGeo::samples() int CSamplesGeo::samples()
{ {
CGeoLatitude lat1(20.0, CAngleUnit::deg()); CLatitude lat1(20.0, CAngleUnit::deg());
CGeoLatitude lat2 = lat1; CLatitude lat2 = lat1;
CGeoLatitude lat3 = lat1 - lat2; CLatitude lat3 = lat1 - lat2;
qDebug() << lat1 << lat2 << lat3; qDebug() << lat1 << lat2 << lat3;
qDebug() << (lat1 + lat2) << (lat1 - lat2); qDebug() << (lat1 + lat2) << (lat1 - lat2);
lat3 += lat1; lat3 += lat1;
CGeoLongitude lon1(33.0, CAngleUnit::deg()); CLongitude lon1(33.0, CAngleUnit::deg());
qDebug() << lon1 << lat3; qDebug() << lon1 << lat3;
// lat3 += lon1; // must not work // lat3 += lon1; // must not work

View File

@@ -72,7 +72,9 @@ HEADERS += \
coordinategeodetic.h \ coordinategeodetic.h \
coordinateecef.h \ coordinateecef.h \
coordinatened.h \ coordinatened.h \
geoearthangle.h geoearthangle.h \
coordinatetransformation.h \
mathmatrix1x3.h
SOURCES += \ SOURCES += \
logmessage.cpp \ logmessage.cpp \
@@ -104,6 +106,7 @@ SOURCES += \
mathvector3dbase.cpp \ mathvector3dbase.cpp \
mathmatrixbase.cpp \ mathmatrixbase.cpp \
mathmatrix3x3.cpp \ mathmatrix3x3.cpp \
mathematics.cpp mathematics.cpp \
coordinatetransformation.cpp
DESTDIR = ../../lib DESTDIR = ../../lib

View File

@@ -21,8 +21,8 @@ class CCoordinateGeodetic : public CBaseStreamStringifier<CCoordinateGeodetic>
{ {
private: private:
CGeoLatitude m_latitude; //!< Latitude CLatitude m_latitude; //!< Latitude
CGeoLongitude m_longitude; //!< Longitude CLongitude m_longitude; //!< Longitude
BlackMisc::PhysicalQuantities::CLength m_height; //!< height BlackMisc::PhysicalQuantities::CLength m_height; //!< height
protected: protected:
@@ -55,7 +55,7 @@ public:
* \param longitude * \param longitude
* \param height * \param height
*/ */
CCoordinateGeodetic(CGeoLatitude latitude, CGeoLongitude longitude, BlackMisc::PhysicalQuantities::CLength height) : CCoordinateGeodetic(CLatitude latitude, CLongitude longitude, BlackMisc::PhysicalQuantities::CLength height) :
m_latitude(latitude), m_longitude(longitude), m_height(height) {} m_latitude(latitude), m_longitude(longitude), m_height(height) {}
/*! /*!
@@ -72,7 +72,7 @@ public:
* \brief Latitude * \brief Latitude
* \return * \return
*/ */
CGeoLatitude latitude() const CLatitude latitude() const
{ {
return this->m_latitude; return this->m_latitude;
} }
@@ -81,7 +81,7 @@ public:
* \brief Longitude * \brief Longitude
* \return * \return
*/ */
CGeoLongitude longitude() const CLongitude longitude() const
{ {
return this->m_longitude; return this->m_longitude;
} }
@@ -99,7 +99,7 @@ public:
* \brief Set latitude * \brief Set latitude
* \param latitude * \param latitude
*/ */
void setLatitude(CGeoLatitude latitude) void setLatitude(CLatitude latitude)
{ {
this->m_latitude = latitude; this->m_latitude = latitude;
} }
@@ -108,7 +108,7 @@ public:
* \brief Set longitude * \brief Set longitude
* \param latitude * \param latitude
*/ */
void setLongitude(CGeoLongitude longitude) void setLongitude(CLongitude longitude)
{ {
this->m_longitude = longitude; this->m_longitude = longitude;
} }

View File

@@ -6,6 +6,8 @@
#ifndef BLACKMISC_COORDINATENED_H #ifndef BLACKMISC_COORDINATENED_H
#define BLACKMISC_COORDINATENED_H #define BLACKMISC_COORDINATENED_H
#include "blackmisc/mathvector3dbase.h" #include "blackmisc/mathvector3dbase.h"
#include "blackmisc/mathmatrix3x3.h"
#include "blackmisc/coordinategeodetic.h"
namespace BlackMisc namespace BlackMisc
{ {
@@ -16,19 +18,94 @@ namespace Geo
*/ */
class CCoordinateNed : public BlackMisc::Math::CVector3DBase<CCoordinateNed> class CCoordinateNed : public BlackMisc::Math::CVector3DBase<CCoordinateNed>
{ {
private:
CCoordinateGeodetic m_referencePosition; //!< geodetic reference position
bool m_hasReferencePosition; //!< valid reference position?
public: public:
/*! /*!
* \brief Default constructor * \brief Default constructor
*/ */
CCoordinateNed() : CVector3DBase() {} CCoordinateNed() : CVector3DBase(), m_hasReferencePosition(false) {}
/*!
* \brief Constructor with reference position
* \param referencePosition
*/
CCoordinateNed(const CCoordinateGeodetic &referencePosition) : CVector3DBase(), m_referencePosition(referencePosition), m_hasReferencePosition(true) {}
/*! /*!
* \brief Constructor by values * \brief Constructor by values
* \param referencePosition
* \param north * \param north
* \param east * \param east
* \param down * \param down
*/ */
CCoordinateNed(qreal north, qreal east, qreal down) : CVector3DBase(north, east, down) {} CCoordinateNed(const CCoordinateGeodetic &referencePosition, qreal north, qreal east, qreal down) : CVector3DBase(north, east, down), m_referencePosition(referencePosition), m_hasReferencePosition(true) {}
/*!
* \brief Copy constructor
* \param otherNed
*/
CCoordinateNed(const CCoordinateNed &otherNed) :
CVector3DBase(otherNed) , m_hasReferencePosition(otherNed.m_hasReferencePosition), m_referencePosition(otherNed.m_referencePosition) {}
/*!
* \brief Equal operator ==
* \param otherNed
* \return
*/
bool operator ==(const CCoordinateNed &otherNed) const
{
if (this == &otherNed) return true;
return this->m_hasReferencePosition == otherNed.m_hasReferencePosition &&
this->m_referencePosition == otherNed.m_referencePosition &&
CVector3DBase::operator== (otherNed);
}
/*!
* \brief Unequal operator !=
* \param otherNed
* \return
*/
bool operator !=(const CCoordinateNed &otherNed) const
{
if (this == &otherNed) return false;
return !((*this) == otherNed);
}
/*!
* \brief Assigment operator =
* \param otherNed
* \return
*/
CCoordinateNed &operator =(const CCoordinateNed &otherNed)
{
if (this == &otherNed) return *this; // Same object?
CVector3DBase::operator = (otherNed);
this->m_hasReferencePosition = otherNed.m_hasReferencePosition;
this->m_referencePosition = otherNed.m_referencePosition;
return (*this);
}
/*!
* \brief Corresponding reference position
* \return
*/
CCoordinateGeodetic referencePosition() const
{
return this->m_referencePosition;
}
/*!
* \brief Corresponding reference position
* \return
*/
bool hasReferencePosition() const
{
return this->m_hasReferencePosition;
}
/*! /*!
* \brief North * \brief North
@@ -83,6 +160,17 @@ public:
{ {
this->m_vector.setZ(down); this->m_vector.setZ(down);
} }
/*!
* \brief Corresponding reference position
* \param referencePosition
*/
void setReferencePosition(const CCoordinateGeodetic &referencePosition)
{
this->m_referencePosition = referencePosition;
this->m_hasReferencePosition = true;
}
}; };
} // namespace } // namespace

View File

@@ -0,0 +1,63 @@
/* Copyright (C) 2013 VATSIM Community / authors
* 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 "coordinatetransformation.h"
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Math;
namespace BlackMisc
{
namespace Geo
{
/*
* NED to ECEF
*/
CCoordinateEcef CCoordinateTransformation::toEcef(const CCoordinateNed &ned)
{
CLatitude lat = ned.referencePosition().latitude();
lat.switchUnit(CAngleUnit::rad());
CLongitude lon = ned.referencePosition().longitude();
lon.switchUnit(CAngleUnit::rad());
double angleRad = - (lat.unitValueToDouble()) - BlackMisc::Math::PI / 2;
CMatrix3x3 dcm1;
CMatrix3x3 dcm2;
CMatrix3x3 dcm3;
CMatrix3x3 dcm;
CMatrix3x3 invDcm;
dcm1.setToIdentity();
dcm2.setZero();
dcm3.setZero();
dcm2(0, 0) = cos(angleRad);
dcm2(0, 2) = -sin(angleRad);
dcm2(1, 1) = 1;
dcm2(2, 0) = sin(angleRad);
dcm2(2, 2) = cos(angleRad);
angleRad = lon.unitValueToDouble();
dcm3(0, 0) = cos(angleRad);
dcm3(0, 1) = sin(angleRad);
dcm3(1, 0) = -sin(angleRad);
dcm3(1, 1) = cos(angleRad);
dcm3(2, 2) = 1;
dcm = dcm1 * dcm2 * dcm3;
invDcm.setZero();
invDcm = dcm.inverse();
CCoordinateNed tempResult(ned);
tempResult.matrixMultiplication(invDcm);
CCoordinateEcef result(tempResult.north(), tempResult.east(), tempResult.down());
return result;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,44 @@
/* Copyright (C) 2013 VATSIM Community / authors
* 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/. */
#ifndef BLACKMISC_COORDINATETRANSFORMATION_H
#define BLACKMISC_COORDINATETRANSFORMATION_H
#include "blackmisc/coordinateecef.h"
#include "blackmisc/coordinatened.h"
#include "blackmisc/coordinategeodetic.h"
#include "blackmisc/mathmatrix3x3.h"
#include "blackmisc/mathematics.h"
namespace BlackMisc
{
namespace Geo
{
/*!
* \brief Coordinate transformation class between different systems
*/
class CCoordinateTransformation
{
private:
/*!
* \brief Default constructor, avoid object instantiation
*/
CCoordinateTransformation() {}
public:
/*!
* \brief NED to ECEF
* \param ned
* \return
*/
static CCoordinateEcef toEcef(const CCoordinateNed &ned);
};
} // namespace
} // namespace
#endif // guard

View File

@@ -14,33 +14,33 @@ namespace Geo
/*! /*!
* \brief Base class for latitude / longitude * \brief Base class for latitude / longitude
*/ */
template <class LATorLON> class CGeoEarthAngle : public BlackMisc::PhysicalQuantities::CAngle template <class LATorLON> class CEarthAngle : public BlackMisc::PhysicalQuantities::CAngle
{ {
protected: protected:
/*! /*!
* \brief Default constructor * \brief Default constructor
*/ */
CGeoEarthAngle() : CAngle() {} CEarthAngle() : CAngle() {}
/*! /*!
* \brief Copy constructor * \brief Copy constructor
* \param latOrLon * \param latOrLon
*/ */
CGeoEarthAngle(const LATorLON &latOrLon) : CAngle(latOrLon) { } CEarthAngle(const LATorLON &latOrLon) : CAngle(latOrLon) { }
/*! /*!
* \brief Init by double value * \brief Init by double value
* \param value * \param value
* \param unit * \param unit
*/ */
CGeoEarthAngle(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CAngle(value, unit) {} CEarthAngle(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CAngle(value, unit) {}
public: public:
/*! /*!
* \brief Virtual destructor * \brief Virtual destructor
*/ */
virtual ~CGeoEarthAngle() {} virtual ~CEarthAngle() {}
/*! /*!
* \brief Equal operator == * \brief Equal operator ==
@@ -67,7 +67,7 @@ public:
* \param latOrLon * \param latOrLon
* \return * \return
*/ */
CGeoEarthAngle &operator +=(const CGeoEarthAngle &latOrLon) CEarthAngle &operator +=(const CEarthAngle &latOrLon)
{ {
CAngle::operator +=(latOrLon); CAngle::operator +=(latOrLon);
return (*this); return (*this);
@@ -78,7 +78,7 @@ public:
* \param latOrLon * \param latOrLon
* \return * \return
*/ */
CGeoEarthAngle &operator -=(const CGeoEarthAngle &latOrLon) CEarthAngle &operator -=(const CEarthAngle &latOrLon)
{ {
CAngle::operator -=(latOrLon); CAngle::operator -=(latOrLon);
return (*this); return (*this);
@@ -129,7 +129,7 @@ public:
* \param latOrLon * \param latOrLon
* \return * \return
*/ */
CGeoEarthAngle &operator =(const LATorLON &latOrLon) CEarthAngle &operator =(const LATorLON &latOrLon)
{ {
CAngle::operator =(latOrLon); CAngle::operator =(latOrLon);
return (*this); return (*this);

View File

@@ -10,7 +10,7 @@ namespace Geo
/*! /*!
* \brief Latitude * \brief Latitude
*/ */
class CGeoLatitude : public CGeoEarthAngle<CGeoLatitude> class CLatitude : public CEarthAngle<CLatitude>
{ {
protected: protected:
/*! /*!
@@ -19,32 +19,32 @@ protected:
virtual QString stringForConverter() const virtual QString stringForConverter() const
{ {
QString s = "latitude "; QString s = "latitude ";
return s.append(CGeoEarthAngle::stringForConverter()); return s.append(CEarthAngle::stringForConverter());
} }
public: public:
/*! /*!
* \brief Default constructor * \brief Default constructor
*/ */
CGeoLatitude() : CGeoEarthAngle() {} CLatitude() : CEarthAngle() {}
/*! /*!
* \brief Copy constructor * \brief Copy constructor
* \param latitude * \param latitude
*/ */
CGeoLatitude(const CGeoLatitude &latitude) : CGeoEarthAngle(latitude) {} CLatitude(const CLatitude &latitude) : CEarthAngle(latitude) {}
/*! /*!
* \brief Init by double value * \brief Init by double value
* \param value * \param value
* \param unit * \param unit
*/ */
CGeoLatitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CGeoEarthAngle(value, unit) {} CLatitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CEarthAngle(value, unit) {}
/*! /*!
* \brief Virtual destructor * \brief Virtual destructor
*/ */
virtual ~CGeoLatitude() {} virtual ~CLatitude() {}
}; };
} // namespace } // namespace

View File

@@ -10,7 +10,7 @@ namespace Geo
/*! /*!
* \brief Longitude * \brief Longitude
*/ */
class CGeoLongitude : public CGeoEarthAngle<CGeoLongitude> class CLongitude : public CEarthAngle<CLongitude>
{ {
protected: protected:
/*! /*!
@@ -19,32 +19,32 @@ protected:
virtual QString stringForConverter() const virtual QString stringForConverter() const
{ {
QString s = "longitude "; QString s = "longitude ";
return s.append(CGeoEarthAngle::stringForConverter()); return s.append(CEarthAngle::stringForConverter());
} }
public: public:
/*! /*!
* \brief Default constructor * \brief Default constructor
*/ */
CGeoLongitude() : CGeoEarthAngle() {} CLongitude() : CEarthAngle() {}
/*! /*!
* \brief Copy constructor * \brief Copy constructor
* \param Longitude * \param Longitude
*/ */
CGeoLongitude(const CGeoLongitude &Longitude) : CGeoEarthAngle(Longitude) {} CLongitude(const CLongitude &Longitude) : CEarthAngle(Longitude) {}
/*! /*!
* \brief Init by double value * \brief Init by double value
* \param value * \param value
* \param unit * \param unit
*/ */
CGeoLongitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CGeoEarthAngle(value, unit) {} CLongitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit): CEarthAngle(value, unit) {}
/*! /*!
* \brief Virtual destructor * \brief Virtual destructor
*/ */
virtual ~CGeoLongitude() {} virtual ~CLongitude() {}
}; };
} // namespace } // namespace

View File

@@ -14,7 +14,7 @@ namespace Math
/* /*
* Hypotenuse * Hypotenuse
*/ */
double CMath::hypot(double x, double y) qreal CMath::hypot(qreal x, qreal y)
{ {
x = abs(x); x = abs(x);
y = abs(y); y = abs(y);
@@ -27,7 +27,7 @@ double CMath::hypot(double x, double y)
/* /*
* Real part of cubic root * Real part of cubic root
*/ */
double CMath::cubicRootReal(const double x) qreal CMath::cubicRootReal(qreal x)
{ {
double result; double result;
result = std::pow(std::abs(x), (double)1 / 3); result = std::pow(std::abs(x), (double)1 / 3);

View File

@@ -5,32 +5,42 @@
#ifndef BLACKMISC_MATHEMATICS_H #ifndef BLACKMISC_MATHEMATICS_H
#define BLACKMISC_MATHEMATICS_H #define BLACKMISC_MATHEMATICS_H
#include <QtCore/qmath.h>
namespace BlackMisc namespace BlackMisc
{ {
namespace Math namespace Math
{ {
// Some namespace wide constant values
//! Mathematical constant Pi
const qreal PI = 4.0 * qAtan(1.0);
//! 2 * Pi
const qreal TwoPI = 2.0 * PI;
/*! /*!
* \brief Math utils * \brief Math utils
*/ */
class CMath class CMath
{ {
public: public:
/*! /*!
* \brief Calculates the hypotenuse of x and y without overflow * \brief Calculates the hypotenuse of x and y without overflow
* \param x * \param x
* \param y * \param y
* \return * \return
*/ */
static double hypot(double x, double y); static qreal hypot(qreal x, qreal y);
/*! /*!
* \brief Calculates the square of x * \brief Calculates the square of x
* \param x * \param x
* \return * \return
*/ */
static inline double square(const double x) static inline qreal square(qreal x)
{ {
return x * x; return x * x;
} }
@@ -40,7 +50,7 @@ public:
* \param x * \param x
* \return * \return
*/ */
static inline double cubic(const double x) static inline qreal cubic(const qreal x)
{ {
return x * x * x; return x * x * x;
} }
@@ -50,7 +60,7 @@ public:
* \param x * \param x
* \return * \return
*/ */
static double cubicRootReal(const double x); static qreal cubicRootReal(qreal x);
private: private:
/*! /*!

View File

@@ -0,0 +1,58 @@
/* Copyright (C) 2013 VATSIM Community / authors
* 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/. */
#ifndef BLACKMISC_POSMATRIX1x3_H
#define BLACKMISC_POSMATRIX1x3_H
#include "blackmisc/mathmatrixbase.h"
#include "blackmisc/mathvector3d.h"
namespace BlackMisc
{
namespace Math
{
/*!
* \brief 3D matrix
*/
class CMatrix1x3 : public CMatrixBase<CMatrix1x3, 1, 3>
{
public:
/*!
* \brief Matrix 1x3
*/
CMatrix1x3() : CMatrixBase() {}
/*!
* \brief init with value
* \param fillValue
*/
CMatrix1x3(qreal fillValue) : CMatrixBase(fillValue) {}
/*!
* \brief Copy constructor
* \param other
*/
CMatrix1x3(const CMatrix1x3 &otherMatrix) : CMatrixBase(otherMatrix) {}
/*!
* \brief CMatrix 3x1
* \param c1
* \param c2
* \param c3
*/
CMatrix1x3(qreal c1, qreal c2, qreal c3) : CMatrixBase()
{
this->m_matrix(0, 0) = c1;
this->m_matrix(0, 1) = c2;
this->m_matrix(0, 2) = c3;
}
};
} // namespace
} // namespace
#endif // guard

View File

@@ -15,16 +15,31 @@ namespace Math
{ {
/*! /*!
* \brief 3D matrix * \brief Matrix 3x1
*/ */
class CMatrix3x1 : public CMatrixBase<CMatrix3x1, 3, 1> class CMatrix3x1 : public CMatrixBase<CMatrix3x1, 3, 1>
{ {
friend class CMatrix3x3; // for matrix multiplicaion to access m_matrix
public: public:
/*! /*!
* \brief CMatrix3D * \brief CMatrix 3x1
*/ */
CMatrix3x1() : CMatrixBase() {} CMatrix3x1() : CMatrixBase() {}
/*!
* \brief CMatrix 3x1
* \param r1
* \param r2
* \param r3
*/
CMatrix3x1(qreal r1, qreal r2, qreal r3) : CMatrixBase()
{
this->m_matrix(0, 0) = r1;
this->m_matrix(1, 0) = r2;
this->m_matrix(2, 0) = r3;
}
/*! /*!
* \brief init with value * \brief init with value
* \param fillValue * \param fillValue
@@ -52,9 +67,9 @@ public:
*/ */
void fromVector3D(const CVector3D &vector) void fromVector3D(const CVector3D &vector)
{ {
this->m_matrix[0][0] = vector.x(); this->m_matrix(0, 0) = vector.i();
this->m_matrix[1][0] = vector.y(); this->m_matrix(1, 0) = vector.j();
this->m_matrix[2][0] = vector.z(); this->m_matrix(2, 0) = vector.k();
} }
}; };

View File

@@ -52,6 +52,30 @@ CMatrix3x3 CMatrix3x3::inverse() const
return inverse; return inverse;
} }
/*
* Get a row
*/
CMatrix1x3 CMatrix3x3::getRow(int row) const
{
bool valid = row >= 0 && row <= 3;
Q_ASSERT_X(valid, "getRow", "invalid row");
if (!valid) throw new std::range_error("invalid row");
return CMatrix1x3(this->getElement(row, 0), this->getElement(row, 1), this->getElement(row, 2));
}
/*
* Get a column
*/
CMatrix3x1 CMatrix3x3::getColumn(int column) const
{
bool valid = column >= 0 && column <= 3;
Q_ASSERT_X(valid, "getColumn", "invalid column");
if (!valid) throw new std::range_error("invalid column");
return CMatrix3x1(this->getElement(0, column), this->getElement(1, column), this->getElement(2, column));
}
} // namespace } // namespace
} // namespace } // namespace

View File

@@ -5,8 +5,8 @@
#ifndef BLACKMISC_POSMATRIX3X3_H #ifndef BLACKMISC_POSMATRIX3X3_H
#define BLACKMISC_POSMATRIX3X3_H #define BLACKMISC_POSMATRIX3X3_H
#include "blackmisc/mathmatrix1x3.h"
#include "blackmisc/mathmatrixbase.h" #include "blackmisc/mathmatrix3x1.h"
namespace BlackMisc namespace BlackMisc
{ {
@@ -14,7 +14,7 @@ namespace Math
{ {
/*! /*!
* \brief 3x1 matrix * \brief 3x3 matrix
*/ */
class CMatrix3x3 : public CMatrixBase<CMatrix3x3, 3, 3> class CMatrix3x3 : public CMatrixBase<CMatrix3x3, 3, 3>
{ {
@@ -48,6 +48,66 @@ public:
*/ */
CMatrix3x3 inverse() const; CMatrix3x3 inverse() const;
/*!
* \brief Operator *=
* \param otherMatrix
* \return
*/
CMatrix3x3 &operator *=(const CMatrix3x3 &otherMatrix)
{
this->m_matrix = this->m_matrix * otherMatrix.m_matrix;
return (*this);
}
/*!
* \brief Operator *
* \param otherMatrix
* \return
*/
CMatrix3x1 operator *(const CMatrix3x1 &otherMatrix) const
{
CMatrix3x1 m;
m.m_matrix = this->m_matrix * otherMatrix.m_matrix;
return m;
}
/*!
* \brief Operator *
* \param multiply
* \return
*/
CMatrix3x3 operator *(const CMatrix3x3 &otherMatrix) const
{
CMatrix3x3 m(otherMatrix);
m *= otherMatrix;
return m;
}
/*!
* \brief Transposed matrix
* \return
*/
CMatrix3x3 transposed() const
{
CMatrix3x3 m(0.0);
m.m_matrix = this->m_matrix.transposed();
return m;
}
/*!
* \brief Get column
* \param column
* \return
*/
CMatrix3x1 getColumn(int column) const;
/*!
* \brief Get row
* \param column
* \return
*/
CMatrix1x3 getRow(int column) const;
}; };
} // namespace } // namespace

View File

@@ -14,12 +14,29 @@ namespace Math
/* /*
* Get element by column / row * Get element by column / row
*/ */
template<class ImplMatrix, int Rows, int Columns> double CMatrixBase<ImplMatrix, Rows, Columns>::getElement(size_t row, size_t column) const template<class ImplMatrix, int Rows, int Columns> qreal CMatrixBase<ImplMatrix, Rows, Columns>::getElement(size_t row, size_t column) const
{
this->checkRange(row, column);
return this->m_matrix(row, column);
}
/*
* Set element by column / row
*/
template<class ImplMatrix, int Rows, int Columns> void CMatrixBase<ImplMatrix, Rows, Columns>::setElement(size_t row, size_t column, qreal value)
{
this->checkRange(row, column);
this->m_matrix(row, column) = value;
}
/*
* Check range
*/
template<class ImplMatrix, int Rows, int Columns> void CMatrixBase<ImplMatrix, Rows, Columns>::checkRange(size_t row, size_t column) const
{ {
bool valid = (row >= 0 && column >= 0 && row < Rows && column < Columns); bool valid = (row >= 0 && column >= 0 && row < Rows && column < Columns);
Q_ASSERT_X(valid, "getElement()", "Row or column invalid"); Q_ASSERT_X(valid, "getElement()", "Row or column invalid");
std::range_error("Row or column invalid"); if (!valid) throw std::range_error("Row or column invalid");
return this->m_matrix(row, column);
} }
/* /*
@@ -57,11 +74,11 @@ template <class ImplMatrix, int Rows, int Columns> QString CMatrixBase<ImplMatri
return s; return s;
} }
// see here for the reason of thess forward instantiations // see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html // http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CMatrixBase<CMatrix3x3, 3, 3>; template class CMatrixBase<CMatrix3x3, 3, 3>;
template class CMatrixBase<CMatrix3x1, 3, 1>; template class CMatrixBase<CMatrix3x1, 3, 1>;
template class CMatrixBase<CMatrix1x3, 1, 3>;
} // namespace } // namespace

View File

@@ -7,6 +7,7 @@
#define BLACKMISC_MATHMATRIXBASE_H #define BLACKMISC_MATHMATRIXBASE_H
#include "blackmisc/basestreamstringifier.h" #include "blackmisc/basestreamstringifier.h"
#include "blackmisc/mathvector3dbase.h"
#include <QGenericMatrix> #include <QGenericMatrix>
namespace BlackMisc namespace BlackMisc
@@ -17,11 +18,12 @@ namespace Math
/*! /*!
* \brief Base functionality of a matrix * \brief Base functionality of a matrix
*/ */
template<class ImplMatrix, int Rows, int Columns> class CMatrixBase : template<class ImplMatrix, int Rows, int Columns> class CMatrixBase : public BlackMisc::CBaseStreamStringifier<ImplMatrix>
public BlackMisc::CBaseStreamStringifier<ImplMatrix>
{ {
protected: protected:
QGenericMatrix<Rows, Columns, qreal> m_matrix; //!< backing data // no bug, Qt expects columns rows
QGenericMatrix<Columns, Rows, qreal> m_matrix; //!< backing data
/*! /*!
* \brief Conversion to string * \brief Conversion to string
@@ -72,7 +74,6 @@ public:
{ {
if (this == &otherMatrix) return false; if (this == &otherMatrix) return false;
return !((*this) == otherMatrix); return !((*this) == otherMatrix);
} }
/*! /*!
@@ -87,30 +88,6 @@ public:
return (*this); return (*this);
} }
/*!
* \brief Operator *=
* \param multiply
* \return
*/
CMatrixBase &operator *=(const CMatrixBase &otherMatrix)
{
this->m_matrix = this->m_matrix * otherMatrix.m_matrix;
return (*this);
}
/*!
* \brief Operator *
* \param multiply
* \return
*/
ImplMatrix operator *(const ImplMatrix &otherMatrix) const
{
ImplMatrix m(0.0);
m += (*this);
m *= otherMatrix;
return m;
}
/*! /*!
* \brief Operator *= * \brief Operator *=
* \param factor * \param factor
@@ -135,6 +112,13 @@ public:
return m; return m;
} }
/*!
* \brief Multiply with 3D vector operator *
* \param vector
* \return
*/
template<class ImplVector> ImplVector operator*(const ImplVector vector) const;
/*! /*!
* \brief Operator /= * \brief Operator /=
* \param factor * \param factor
@@ -207,17 +191,6 @@ public:
return m; return m;
} }
/*!
* \brief Transposed matrix
* \return
*/
ImplMatrix transposed() const
{
ImplMatrix m(0.0);
m.m_matrix = this->m_matrix.transposed();
return m;
}
/*! /*!
* \brief Is identity matrix? * \brief Is identity matrix?
* \return * \return
@@ -255,9 +228,49 @@ public:
/*! /*!
* \brief Get element * \brief Get element
* \param row * \param row
* \param column
* \return * \return
*/ */
double getElement(size_t row, size_t column) const; qreal getElement(size_t row, size_t column) const;
/*!
* \brief Get element
* \param row
* \param column
* \param value
*/
void setElement(size_t row, size_t column, qreal value);
/*!
* \brief Get element by ()
* \param column
* \return
*/
qreal &operator()(size_t row, size_t column)
{
this->checkRange(row, column);
return this->m_matrix(row, column);
}
/*!
* \brief Get element by ()
* \param column
* \return
*/
qreal operator()(size_t row, size_t column) const
{
return this->getElement(row, column);
}
private:
/*!
* \brief Check range of row / column
* \param row
* \param column
* \throws std::range_error if index out of bounds
*/
void checkRange(size_t row, size_t column) const;
}; };
} // namespace } // namespace

View File

@@ -3,8 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blackmisc/mathvector3dbase.h"
#include "blackmisc/mathvector3d.h" #include "blackmisc/mathvector3d.h"
#include "blackmisc/mathmatrix3x3.h"
#include "blackmisc/coordinateecef.h" #include "blackmisc/coordinateecef.h"
#include "blackmisc/coordinatened.h" #include "blackmisc/coordinatened.h"
@@ -46,10 +46,7 @@ template <class ImplClass> void CVector3DBase<ImplClass>::fill(qreal value)
*/ */
template <class ImplClass> qreal CVector3DBase<ImplClass>::getElement(size_t row) const template <class ImplClass> qreal CVector3DBase<ImplClass>::getElement(size_t row) const
{ {
bool validIndex = (row < 3 && row >= 0); qreal d;
Q_ASSERT_X(validIndex, "getElement", "Wrong index");
if (!validIndex) throw std::range_error("Invalid index vor 3D vector");
double d;
switch (row) switch (row)
{ {
case 0: case 0:
@@ -69,6 +66,48 @@ template <class ImplClass> qreal CVector3DBase<ImplClass>::getElement(size_t row
return d; return d;
} }
/*
* Set given element
*/
template <class ImplClass> void CVector3DBase<ImplClass>::setElement(size_t row, qreal value)
{
switch (row)
{
case 0:
this->m_vector.setX(value);
break;
case 1:
this->m_vector.setY(value);
break;
case 2:
this->m_vector.setZ(value);
break;
default:
Q_ASSERT_X(true, "setElement", "Detected invalid index in 3D vector");
throw std::range_error("Detected invalid index in 3D vector");
break;
}
}
/*
* Multiply with matrix
*/
template <class ImplClass> void CVector3DBase<ImplClass>::matrixMultiplication(const CMatrix3x3 &matrix)
{
CMatrix3x1 m = matrix * (this->toMatrix3x1());
this->m_vector.setX(m(0,0));
this->m_vector.setY(m(1,0));
this->m_vector.setZ(m(2,0));
}
/*
* Convert to matrix
*/
template <class ImplClass> CMatrix3x1 CVector3DBase<ImplClass>::toMatrix3x1() const
{
return CMatrix3x1(this->m_vector.x(), this->m_vector.y(), this->m_vector.z());
}
// see here for the reason of thess forward instantiations // see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html // http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CVector3DBase<CVector3D>; template class CVector3DBase<CVector3D>;

View File

@@ -14,6 +14,10 @@ namespace BlackMisc
namespace Math namespace Math
{ {
class CMatrix3x3; // forward declaration
class CMatrix3x1; // forward declaration
/*! /*!
* \brief 3D vector base (x, y, z) * \brief 3D vector base (x, y, z)
*/ */
@@ -75,6 +79,13 @@ public:
*/ */
qreal getElement(size_t row) const; qreal getElement(size_t row) const;
/*!
* \brief Set element
* \param row
* \param value
*/
void setElement(size_t row, qreal value);
/*! /*!
* \brief Operator [] * \brief Operator []
* \param row * \param row
@@ -82,6 +93,14 @@ public:
*/ */
qreal operator[](size_t row) const { return this->getElement(row); } qreal operator[](size_t row) const { return this->getElement(row); }
/*!
* \brief Get element by ()
* \param column
* \return
*/
qreal operator()(size_t row) const { return this->getElement(row); }
/*! /*!
* \brief Equal operator == * \brief Equal operator ==
* \param otherVector * \param otherVector
@@ -106,7 +125,7 @@ public:
/*! /*!
* \brief Assigment operator = * \brief Assigment operator =
* \param multiply * \param otherVector
* \return * \return
*/ */
CVector3DBase &operator =(const CVector3DBase &otherVector) CVector3DBase &operator =(const CVector3DBase &otherVector)
@@ -165,7 +184,7 @@ public:
} }
/*! /*!
* \brief Operator *=, just x*x, y*y, z*z neither vector nor dot product * \brief Operator *=, just x*x, y*y, z*z neither vector nor dot product (like a matrix produc)
* \param otherVector * \param otherVector
* \return * \return
*/ */
@@ -176,7 +195,7 @@ public:
} }
/*! /*!
* \brief Operator, just x*x, y*y, z*z neither vector nor dot product * \brief Operator, just x*x, y*y, z*z neither vector nor dot product, (like a matrix produc)
* \param otherVector * \param otherVector
* \return * \return
*/ */
@@ -223,7 +242,7 @@ public:
} }
/*! /*!
* \brief Dot product * \brief Cross product
* \param otherVector * \param otherVector
* \return * \return
*/ */
@@ -235,7 +254,14 @@ public:
} }
/*! /*!
* \brief Dot product * \brief Matrix * this vector
* \param matrix
* \return
*/
void matrixMultiplication(const CMatrix3x3 &matrix);
/*!
* \brief Reciporcal value
* \param otherVector * \param otherVector
* \return * \return
*/ */
@@ -266,6 +292,12 @@ public:
return this->m_vector.lengthSquared(); return this->m_vector.lengthSquared();
} }
/*!
* \brief Converted to matrix
* \return
*/
CMatrix3x1 toMatrix3x1() const;
/*! /*!
* \brief Magnitude * \brief Magnitude
* \return * \return

View File

@@ -57,16 +57,22 @@ template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator ==(const
// some special cases for best quality // some special cases for best quality
double diff; double diff;
const double lenient = 1.001; // even diff already has a rounding issue to be avoided const double lenient = 1.001; // even diff already has a rounding issue to be avoided
if (this->m_unit == otherQuantity.m_unit) { if (this->m_unit == otherQuantity.m_unit)
{
// same unit // same unit
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue) { if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
{
// pure integer comparison, no rounding issues // pure integer comparison, no rounding issues
return this->m_unitValueI == otherQuantity.m_unitValueI; return this->m_unitValueI == otherQuantity.m_unitValueI;
} else { }
else
{
diff = abs(this->m_unitValueD - otherQuantity.m_unitValueD); diff = abs(this->m_unitValueD - otherQuantity.m_unitValueD);
return diff <= (lenient * this->m_unit.getEpsilon()); return diff <= (lenient * this->m_unit.getEpsilon());
} }
} else { }
else
{
// based on SI value // based on SI value
diff = abs(this->m_convertedSiUnitValueD - otherQuantity.m_convertedSiUnitValueD); diff = abs(this->m_convertedSiUnitValueD - otherQuantity.m_convertedSiUnitValueD);
return diff <= (lenient * this->m_unit.getEpsilon()); return diff <= (lenient * this->m_unit.getEpsilon());
@@ -105,15 +111,21 @@ template <class MU, class PQ> CPhysicalQuantity<MU, PQ>& CPhysicalQuantity<MU, P
*/ */
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator +=(const CPhysicalQuantity<MU, PQ> &otherQuantity) template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator +=(const CPhysicalQuantity<MU, PQ> &otherQuantity)
{ {
if (this->m_unit == otherQuantity.m_unit) { if (this->m_unit == otherQuantity.m_unit)
{
// same unit // same unit
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue) { if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
{
// pure integer, no rounding issues // pure integer, no rounding issues
this->setUnitValue(otherQuantity.m_unitValueI + this->m_unitValueI); this->setUnitValue(otherQuantity.m_unitValueI + this->m_unitValueI);
} else { }
else
{
this->setUnitValue(otherQuantity.m_unitValueD + this->m_unitValueD); this->setUnitValue(otherQuantity.m_unitValueD + this->m_unitValueD);
} }
} else { }
else
{
double v = otherQuantity.value(this->m_unit); double v = otherQuantity.value(this->m_unit);
this->setUnitValue(v + this->m_unitValueD); this->setUnitValue(v + this->m_unitValueD);
} }
@@ -152,15 +164,21 @@ template <class MU, class PQ> void CPhysicalQuantity<MU, PQ>::substractUnitValue
*/ */
template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator -=(const CPhysicalQuantity<MU, PQ> &otherQuantity) template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::operator -=(const CPhysicalQuantity<MU, PQ> &otherQuantity)
{ {
if (this->m_unit == otherQuantity.m_unit) { if (this->m_unit == otherQuantity.m_unit)
{
// same unit // same unit
if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue) { if (this->m_isIntegerBaseValue && otherQuantity.m_isIntegerBaseValue)
{
// pure integer, no rounding issues // pure integer, no rounding issues
this->setUnitValue(otherQuantity.m_unitValueI - this->m_unitValueI); this->setUnitValue(otherQuantity.m_unitValueI - this->m_unitValueI);
} else { }
else
{
this->setUnitValue(otherQuantity.m_unitValueD - this->m_unitValueD); this->setUnitValue(otherQuantity.m_unitValueD - this->m_unitValueD);
} }
} else { }
else
{
double v = otherQuantity.value(this->m_unit); double v = otherQuantity.value(this->m_unit);
this->setUnitValue(v - this->m_unitValueD); this->setUnitValue(v - this->m_unitValueD);
} }
@@ -258,14 +276,13 @@ template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::operator <=(const
/* /*
* Switch to another unit * Switch to another unit
*/ */
template <class MU, class PQ> bool CPhysicalQuantity<MU, PQ>::switchUnit(const MU &newUnit) template <class MU, class PQ> CPhysicalQuantity<MU, PQ> &CPhysicalQuantity<MU, PQ>::switchUnit(const MU &newUnit)
{ {
if (this->m_unit == newUnit) return true; if (this->m_unit == newUnit) return *this;
if (this->m_unit.getType() != newUnit.getType()) return false; // not possible
double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit); double cf = this->m_unit.conversionToUnit(this->m_unitValueD, newUnit);
this->m_unit = newUnit; this->m_unit = newUnit;
this->setUnitValue(cf); this->setUnitValue(cf);
return true; return *this;
} }
/* /*

View File

@@ -111,7 +111,7 @@ public:
* \param newUnit * \param newUnit
* \return * \return
*/ */
bool switchUnit(const MU &newUnit); CPhysicalQuantity &switchUnit(const MU &newUnit);
/*! /*!
* \brief Value in SI base unit? Meter is an SI base unit, hertz not! * \brief Value in SI base unit? Meter is an SI base unit, hertz not!