diff --git a/samples/blackmiscvectorgeo/samplesvectormatrix.cpp b/samples/blackmiscvectorgeo/samplesvectormatrix.cpp index cee116495..3408f8d54 100644 --- a/samples/blackmiscvectorgeo/samplesvectormatrix.cpp +++ b/samples/blackmiscvectorgeo/samplesvectormatrix.cpp @@ -18,9 +18,10 @@ int BlackMiscTest::CSamplesVectorMatrix::samples() CMatrix3x3 mr = m; qDebug() << m << mr; mr.setRandom(); - CMatrix3x3 mi = mr.inverse(); + bool im; + CMatrix3x3 mi = mr.inverse(im); CMatrix3x3 mid = mr * mi; - qDebug() << mr << mi << mid; + qDebug() << mr << mi << mid << im; // bye qDebug() << "-----------------------------------------------"; diff --git a/src/blackmisc/coordinatetransformation.cpp b/src/blackmisc/coordinatetransformation.cpp index 113c5b425..d41b15e71 100644 --- a/src/blackmisc/coordinatetransformation.cpp +++ b/src/blackmisc/coordinatetransformation.cpp @@ -51,8 +51,10 @@ CCoordinateEcef CCoordinateTransformation::toEcef(const CCoordinateNed &ned) dcm = dcm1 * dcm2 * dcm3; + bool inverse; invDcm.setZero(); - invDcm = dcm.inverse(); + invDcm = dcm.inverse(inverse); + Q_ASSERT_X(inverse, "toEcef", "Inverse matrix could not be calculated"); CVector3D tempResult = invDcm * ned.toMathVector(); // to generic vector CCoordinateEcef result(tempResult); diff --git a/src/blackmisc/mathmatrix1x3.h b/src/blackmisc/mathmatrix1x3.h index 53694d32e..6a90a32ac 100644 --- a/src/blackmisc/mathmatrix1x3.h +++ b/src/blackmisc/mathmatrix1x3.h @@ -25,18 +25,18 @@ public: */ CMatrix1x3() : CMatrixBase() {} - /*! - * \brief init with value - * \param fillValue - */ - CMatrix1x3(double fillValue) : CMatrixBase(fillValue) {} - /*! * \brief Copy constructor * \param other */ CMatrix1x3(const CMatrix1x3 &otherMatrix) : CMatrixBase(otherMatrix) {} + /*! + * \brief Init by fill value + * \param fillValue + */ + explicit CMatrix1x3(double fillValue) : CMatrixBase(fillValue) {} + /*! * \brief CMatrix 3x1 * \param c1 diff --git a/src/blackmisc/mathmatrix3x1.h b/src/blackmisc/mathmatrix3x1.h index 405514d2b..eec8fd622 100644 --- a/src/blackmisc/mathmatrix3x1.h +++ b/src/blackmisc/mathmatrix3x1.h @@ -40,18 +40,18 @@ public: this->m_matrix(2, 0) = r3; } - /*! - * \brief init with value - * \param fillValue - */ - CMatrix3x1(qreal fillValue) : CMatrixBase(fillValue) {} - /*! * \brief Copy constructor * \param other */ CMatrix3x1(const CMatrix3x1 &otherMatrix) : CMatrixBase(otherMatrix) {} + /*! + * \brief Init by fill value + * \param fillValue + */ + explicit CMatrix3x1(double fillValue) : CMatrixBase(fillValue) {} + /*! * \brief Convert to vector * \return diff --git a/src/blackmisc/mathmatrix3x3.cpp b/src/blackmisc/mathmatrix3x3.cpp index d3e51f3d4..a754f1b8a 100644 --- a/src/blackmisc/mathmatrix3x3.cpp +++ b/src/blackmisc/mathmatrix3x3.cpp @@ -13,9 +13,9 @@ namespace Math /* * Determinant */ -qreal CMatrix3x3::determinant() const +double CMatrix3x3::determinant() const { - qreal determinant = + double determinant = this->m_matrix(0, 0) * this->m_matrix(1, 1) * this->m_matrix(2, 2) + this->m_matrix(0, 1) * this->m_matrix(1, 2) * this->m_matrix(2, 0) + this->m_matrix(0, 2) * this->m_matrix(1, 0) * this->m_matrix(2, 1) - @@ -27,17 +27,19 @@ qreal CMatrix3x3::determinant() const } /* - * Determinant + * Inverse */ -CMatrix3x3 CMatrix3x3::inverse() const +CMatrix3x3 CMatrix3x3::inverse(bool &invertible) const { CMatrix3x3 inverse; - qreal det = determinant(); - - // should we throw an assert / error here? - if (det == 0) return inverse; - - qreal invdet = 1.0 / det; + double det; + if (this->allValuesEqual() || (det = determinant()) == 0) + { + invertible = false; + inverse.setZero(); + return inverse; + } + double invdet = 1.0 / det; inverse.m_matrix(0, 0) = (this->m_matrix(1, 1) * this->m_matrix(2, 2) - this->m_matrix(1, 2) * this->m_matrix(2, 1)) * invdet; inverse.m_matrix(0, 1) = (- this->m_matrix(0, 1) * this->m_matrix(2, 2) + this->m_matrix(0, 2) * this->m_matrix(2, 1)) * invdet; @@ -49,6 +51,7 @@ CMatrix3x3 CMatrix3x3::inverse() const inverse.m_matrix(2, 1) = (- this->m_matrix(0, 0) * this->m_matrix(2, 1) + this->m_matrix(0, 1) * this->m_matrix(2, 0)) * invdet; inverse.m_matrix(2, 2) = (this->m_matrix(0, 0) * this->m_matrix(1, 1) - this->m_matrix(0, 1) * this->m_matrix(1, 0)) * invdet; + invertible = true; return inverse; } diff --git a/src/blackmisc/mathmatrix3x3.h b/src/blackmisc/mathmatrix3x3.h index 7fb438049..57fef0079 100644 --- a/src/blackmisc/mathmatrix3x3.h +++ b/src/blackmisc/mathmatrix3x3.h @@ -24,18 +24,45 @@ public: */ CMatrix3x3() : CMatrixBase() {} - /*! - * \brief init with value - * \param fillValue - */ - CMatrix3x3(double fillValue) : CMatrixBase(fillValue) {} - /*! * \brief Copy constructor * \param other */ CMatrix3x3(const CMatrix3x3 &otherMatrix) : CMatrixBase(otherMatrix) {} + /*! + * \brief Init by fill value + * \param fillValue + */ + explicit CMatrix3x3(double fillValue) : CMatrixBase(fillValue) {} + + /*! + * \brief Stupid but handy constructor + * \param r1c1 + * \param r1c2 + * \param r1c3 + * \param r2c1 + * \param r2c2 + * \param r2c3 + * \param r3c1 + * \param r3c2 + * \param r3c3 + */ + explicit CMatrix3x3(double r1c1, double r1c2, double r1c3, + double r2c1, double r2c2, double r2c3, + double r3c1, double r3c2, double r3c3) : CMatrixBase() + { + this->setElement(0, 0, r1c1); + this->setElement(0, 1, r1c2); + this->setElement(0, 2, r1c3); + this->setElement(1, 0, r2c1); + this->setElement(1, 1, r2c2); + this->setElement(1, 2, r2c3); + this->setElement(2, 0, r3c1); + this->setElement(2, 1, r3c2); + this->setElement(2, 2, r3c3); + } + /*! * \brief Calculates the determinant of the matrix * \return @@ -44,9 +71,10 @@ public: /*! * \brief Calculate the inverse + * \param invertible * \return */ - CMatrix3x3 inverse() const; + CMatrix3x3 inverse(bool &invertible) const; /*! * \brief Operator *= @@ -78,7 +106,7 @@ public: */ CMatrix3x3 operator *(const CMatrix3x3 &otherMatrix) const { - CMatrix3x3 m(otherMatrix); + CMatrix3x3 m(*this); m *= otherMatrix; return m; } @@ -95,13 +123,36 @@ public: return v; } + /*! + * \brief Multiply with factor + * \param factor + * \return + */ + CMatrix3x3 operator *(double factor) const + { + CMatrix3x3 m(*this); + m *= factor; + return m; + } + + /*! + * \brief Multiply with factor + * \param factor + * \return + */ + CMatrix3x3 &operator *=(double factor) + { + CMatrixBase::operator *=(factor); + return (*this); + } + /*! * \brief Transposed matrix * \return */ CMatrix3x3 transposed() const { - CMatrix3x3 m(0.0); + CMatrix3x3 m(0); m.m_matrix = this->m_matrix.transposed(); return m; } @@ -126,4 +177,4 @@ public: } // namespace -#endif // BLACKMISC_POSMATRIX3X3_H +#endif // guard diff --git a/src/blackmisc/mathmatrixbase.cpp b/src/blackmisc/mathmatrixbase.cpp index df0fa3012..44fa3e547 100644 --- a/src/blackmisc/mathmatrixbase.cpp +++ b/src/blackmisc/mathmatrixbase.cpp @@ -68,6 +68,23 @@ template bool CMatrixBase bool CMatrixBase::allValuesEqual() const +{ + double v = this->getElement(0,0); + for (int r = 0; r < Rows; r++) + { + for (int c = 0; c < Columns; c++) + { + if (this->m_matrix(r, c) != v) return false; + } + } + return true; +} + + /* * Convert to string */ diff --git a/src/blackmisc/mathmatrixbase.h b/src/blackmisc/mathmatrixbase.h index 0fffb1e4d..ee1ecc310 100644 --- a/src/blackmisc/mathmatrixbase.h +++ b/src/blackmisc/mathmatrixbase.h @@ -37,18 +37,21 @@ public: */ CMatrixBase() : m_matrix() {} - /*! - * \brief Constructor with init value - * \param fillValue - */ - CMatrixBase(double fillValue) : m_matrix() { this->m_matrix.fill(fillValue);} - /*! * \brief Copy constructor * \param other */ CMatrixBase(const CMatrixBase &otherMatrix) : m_matrix(otherMatrix.m_matrix) {} + /*! + * \brief Fill with value + * \param fillValue + */ + explicit CMatrixBase(double fillValue) : m_matrix() + { + this->fill(fillValue); + } + /*! * \brief Virtual destructor */ @@ -104,9 +107,9 @@ public: * \param factor * \return */ - CMatrixBase &operator *(double factor) + ImplMatrix operator *(double factor) const { - ImplMatrix m(0.0); + ImplMatrix m(0); m += (*this); m *= factor; return m; @@ -135,9 +138,9 @@ public: * \param factor * \return */ - CMatrixBase &operator /(double factor) + ImplMatrix operator /(double factor) const { - ImplMatrix m(0.0); + ImplMatrix m(0); m += (*this); m /= factor; return m; @@ -161,7 +164,7 @@ public: */ ImplMatrix operator +(const ImplMatrix &otherMatrix) const { - ImplMatrix m(0.0); + ImplMatrix m(0); m += (*this); m += otherMatrix; return m; @@ -185,7 +188,7 @@ public: */ ImplMatrix operator -(const ImplMatrix &otherMatrix) const { - ImplMatrix m(0.0); + ImplMatrix m(0); m += (*this); m -= otherMatrix; return m; @@ -220,11 +223,17 @@ public: void setZero() { this->m_matrix.fill(0.0); } /*! - * \brief isZero + * \brief Is zero * \return */ bool isZero() const; + /*! + * \brief All values equal, if so matirx is not invertible + * \return + */ + bool allValuesEqual() const; + /*! * \brief Set a dedicated value * \param value diff --git a/src/blackmisc/mathvector3d.h b/src/blackmisc/mathvector3d.h index 00ae8d8c2..116c7f806 100644 --- a/src/blackmisc/mathvector3d.h +++ b/src/blackmisc/mathvector3d.h @@ -31,7 +31,7 @@ public: * \brief Constructor by value * \param value */ - CVector3D(double value) : CVector3DBase(value) {} + explicit CVector3D(double value) : CVector3DBase(value) {} /*! * \brief Copy constructor diff --git a/src/blackmisc/mathvector3dbase.h b/src/blackmisc/mathvector3dbase.h index dd93c2c14..bcf1c40d1 100644 --- a/src/blackmisc/mathvector3dbase.h +++ b/src/blackmisc/mathvector3dbase.h @@ -46,7 +46,7 @@ protected: * \brief Constructor by value * \param value */ - CVector3DBase(double value) : m_i(value), m_j(value), m_k(value) {} + explicit CVector3DBase(double value) : m_i(value), m_j(value), m_k(value) {} /*! * \brief Copy constructor @@ -225,6 +225,58 @@ public: return v; } + /*! + * \brief Multiply with scalar + * \param factor + * \return + */ + CVector3DBase &operator *=(double factor) + { + this->m_i *= factor; + this->m_j *= factor; + this->m_k *= factor; + return (*this); + } + + /*! + * \brief Multiply with scalar + * \param factor + * \return + */ + ImplClass operator *(double factor) const + { + ImplClass v; + v += (*this); + v *= factor; + return v; + } + + /*! + * \brief Divide by scalar + * \param divisor + * \return + */ + CVector3DBase &operator /=(double divisor) + { + this->m_i /= divisor; + this->m_j /= divisor; + this->m_k /= divisor; + return (*this); + } + + /*! + * \brief Divide by scalar + * \param divisor + * \return + */ + ImplClass operator /(double divisor) const + { + ImplClass v; + v += (*this); + v /= divisor; + return v; + } + /*! * \brief Operator /=, just x/x, y/y, z/z * \param otherVector diff --git a/tests/blackmisc/test_blackmisc.pro b/tests/blackmisc/test_blackmisc.pro index 74a17a3d9..041388c09 100644 --- a/tests/blackmisc/test_blackmisc.pro +++ b/tests/blackmisc/test_blackmisc.pro @@ -11,13 +11,13 @@ INCLUDEPATH += . ../../src SOURCES += main.cpp testmain.cpp \ testphysicalquantitiesbase.cpp \ testaviationbase.cpp \ - testvectormatrix.cpp + testvectormatrixbase.cpp HEADERS += testmain.h \ testphysicalquantitiesbase.h \ blackmisctest.h \ testaviationbase.h \ - testvectormatrix.h + testvectormatrixbase.h win32-msvc* { PRE_TARGETDEPS += ../../lib/blackmisc.lib diff --git a/tests/blackmisc/testmain.cpp b/tests/blackmisc/testmain.cpp index e8e070df7..a4d0859d5 100644 --- a/tests/blackmisc/testmain.cpp +++ b/tests/blackmisc/testmain.cpp @@ -16,7 +16,7 @@ int CTestMain::unitMain(int argc, char *argv[]) { CTestPhysicalQuantitiesBase pqBaseTests ; CTestAviationBase avBaseTests; - CTestVectorMatrix vmTests; + CTestVectorMatrixBase vmTests; status |= QTest::qExec(&pqBaseTests, argc, argv); status |= QTest::qExec(&avBaseTests, argc, argv); status |= QTest::qExec(&vmTests, argc, argv); diff --git a/tests/blackmisc/testmain.h b/tests/blackmisc/testmain.h index 4ce4681e0..259799c55 100644 --- a/tests/blackmisc/testmain.h +++ b/tests/blackmisc/testmain.h @@ -8,7 +8,7 @@ #include "testphysicalquantitiesbase.h" #include "testaviationbase.h" -#include "testvectormatrix.h" +#include "testvectormatrixbase.h" #include namespace BlackMiscTest diff --git a/tests/blackmisc/testvectormatrix.cpp b/tests/blackmisc/testvectormatrix.cpp deleted file mode 100644 index 7036c501e..000000000 --- a/tests/blackmisc/testvectormatrix.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* 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 "testvectormatrix.h" - -using namespace BlackMisc::Math; - -namespace BlackMiscTest -{ - -/* - * Basic tests vector - */ -void CTestVectorMatrix::vectorBasics() -{ - -} - -/* - * Matrix tests - */ -void CTestVectorMatrix::matrixBasics() -{ - CMatrix3x3 m1; - CMatrix3x3 m2 = m1 - m1; - QVERIFY2(m1.isIdentity(), "Default matrix should be identity"); - QVERIFY2(m2.isZero(), "Matrix should be zero"); -} - -} // namespace - -#include "testvectormatrix.h" - diff --git a/tests/blackmisc/testvectormatrixbase.cpp b/tests/blackmisc/testvectormatrixbase.cpp new file mode 100644 index 000000000..144edac3e --- /dev/null +++ b/tests/blackmisc/testvectormatrixbase.cpp @@ -0,0 +1,64 @@ +/* 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 "testvectormatrixbase.h" + +using namespace BlackMisc::Math; + +namespace BlackMiscTest +{ + +/* + * Basic tests vector + */ +void CTestVectorMatrixBase::vectorBasics() +{ + CVector3D v1(1); + v1 *= 2.0; + CVector3D v2(2); + QVERIFY2(v1 == v2, "Matrix should be zero"); +} + +/* + * Matrix tests + * http://www.bluebit.gr/matrix-calculator/ + */ +void CTestVectorMatrixBase::matrixBasics() +{ + CMatrix3x3 m1; + CMatrix3x3 m2 = m1 - m1; + QVERIFY2(m1.isIdentity(), "Default matrix should be identity"); + QVERIFY2(m2.isZero(), "Matrix should be zero"); + + bool invertible; + CMatrix3x3 mr; + CMatrix3x3 msame(3.0); + mr = msame.inverse(invertible); + QVERIFY2(!invertible, "Matrix with sigular values cannot be inverted"); + + mr.setToIdentity(); + QVERIFY2(mr.determinant() == 1, "Identity matrix should have determinant 1"); + mr = mr.inverse(invertible); + QVERIFY2(invertible && mr.isIdentity() == 1, "Identity matrix should have inverse identity"); + + m1.setToIdentity(); + m2 = m1 + m1; + m1 = m1 * 2.0; + QVERIFY2(m1 == m2, "2* Identity should be Identity + Identity"); + + m1 /= 2.0; + m2 -= m1; + QVERIFY2(m1 == m2, "Identity should be Identity"); + + m1 = CMatrix3x3(1, 5, 3, 2, 4, 7, 4, 6, 2); + double det = m1.determinant(); + QVERIFY2(det == 74, qPrintable(QString("Determinant should be 74, but is: %1").arg(det))); + QVERIFY2(m1(0, 0) == 1 && m1(1, 0) == 2 && m1(0, 2) == 3, "Index error"); + CMatrix3x3 mi = m1.inverse(invertible); + CMatrix3x3 mid = m1 * mi; + QVERIFY2(mid.isIdentity(), qPrintable(QString("Multiply with inverse should be identity: %1").arg(mid))); +} + +} // namespace diff --git a/tests/blackmisc/testvectormatrix.h b/tests/blackmisc/testvectormatrixbase.h similarity index 86% rename from tests/blackmisc/testvectormatrix.h rename to tests/blackmisc/testvectormatrixbase.h index f88ed7ce2..f0080328e 100644 --- a/tests/blackmisc/testvectormatrix.h +++ b/tests/blackmisc/testvectormatrixbase.h @@ -15,7 +15,7 @@ namespace BlackMiscTest /*! * \brief Vector and Matrix classes basic tests */ -class CTestVectorMatrix : public QObject +class CTestVectorMatrixBase : public QObject { Q_OBJECT @@ -24,7 +24,7 @@ public: * \brief Standard test case constructor * \param parent */ - explicit CTestVectorMatrix(QObject *parent = 0) : QObject(parent) {} + explicit CTestVectorMatrixBase(QObject *parent = 0) : QObject(parent) {} private slots: /*!