// Copyright (c) 1991-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef _gp_Mat_HeaderFile #define _gp_Mat_HeaderFile #include "gp.hxx" #include "Standard_OutOfRange.hxx" #include "Standard_OStream.hxx" #include "Standard_ConstructionError.hxx" class gp_XYZ; //! Describes a three column, three row matrix. //! This sort of object is used in various vectorial or matrix computations. class gp_Mat { public: DEFINE_STANDARD_ALLOC //! Creates a matrix with null coefficients. constexpr gp_Mat() noexcept : myMat{{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}} { } constexpr gp_Mat(const double theA11, const double theA12, const double theA13, const double theA21, const double theA22, const double theA23, const double theA31, const double theA32, const double theA33) noexcept; //! Creates a matrix. //! theCol1, theCol2, theCol3 are the 3 columns of the matrix. Standard_EXPORT gp_Mat(const gp_XYZ& theCol1, const gp_XYZ& theCol2, const gp_XYZ& theCol3); //! Assigns the three coordinates of theValue to the column of index //! theCol of this matrix. //! Raises OutOfRange if theCol < 1 or theCol > 3. Standard_EXPORT void SetCol(const int theCol, const gp_XYZ& theValue); //! Assigns the number triples theCol1, theCol2, theCol3 to the three //! columns of this matrix. Standard_EXPORT void SetCols(const gp_XYZ& theCol1, const gp_XYZ& theCol2, const gp_XYZ& theCol3); //! Modifies the matrix M so that applying it to any number //! triple (X, Y, Z) produces the same result as the cross //! product of theRef and the number triple (X, Y, Z): //! i.e.: M * {X,Y,Z}t = theRef.Cross({X, Y ,Z}) //! this matrix is anti symmetric. To apply this matrix to the //! triplet {XYZ} is the same as to do the cross product between the //! triplet theRef and the triplet {XYZ}. //! Note: this matrix is anti-symmetric. Standard_EXPORT void SetCross(const gp_XYZ& theRef); //! Modifies the main diagonal of the matrix. //! @code //! .Value (1, 1) = theX1 //! .Value (2, 2) = theX2 //! .Value (3, 3) = theX3 //! @endcode //! The other coefficients of the matrix are not modified. constexpr void SetDiagonal(const double theX1, const double theX2, const double theX3) noexcept { myMat[0][0] = theX1; myMat[1][1] = theX2; myMat[2][2] = theX3; } //! Modifies this matrix so that applying it to any number //! triple (X, Y, Z) produces the same result as the scalar //! product of theRef and the number triple (X, Y, Z): //! this * (X,Y,Z) = theRef.(X,Y,Z) //! Note: this matrix is symmetric. Standard_EXPORT void SetDot(const gp_XYZ& theRef) noexcept; //! Modifies this matrix so that it represents the Identity matrix. constexpr void SetIdentity() noexcept { myMat[0][0] = myMat[1][1] = myMat[2][2] = 1.0; myMat[0][1] = myMat[0][2] = myMat[1][0] = myMat[1][2] = myMat[2][0] = myMat[2][1] = 0.0; } //! Modifies this matrix so that it represents a rotation. theAng is the angular value in //! radians and the XYZ axis gives the direction of the //! rotation. //! Raises ConstructionError if XYZ.Modulus() <= Resolution() Standard_EXPORT void SetRotation(const gp_XYZ& theAxis, const double theAng); //! Assigns the three coordinates of Value to the row of index //! theRow of this matrix. Raises OutOfRange if theRow < 1 or theRow > 3. Standard_EXPORT void SetRow(const int theRow, const gp_XYZ& theValue); //! Assigns the number triples theRow1, theRow2, theRow3 to the three //! rows of this matrix. Standard_EXPORT void SetRows(const gp_XYZ& theRow1, const gp_XYZ& theRow2, const gp_XYZ& theRow3); //! Modifies the matrix so that it represents //! a scaling transformation, where theS is the scale factor. : //! @code //! | theS 0.0 0.0 | //! = | 0.0 theS 0.0 | //! | 0.0 0.0 theS | //! @endcode constexpr void SetScale(const double theS) noexcept { myMat[0][0] = myMat[1][1] = myMat[2][2] = theS; myMat[0][1] = myMat[0][2] = myMat[1][0] = myMat[1][2] = myMat[2][0] = myMat[2][1] = 0.0; } //! Assigns to the coefficient of row theRow, column theCol of this matrix. //! Raises OutOfRange if theRow < 1 or theRow > 3 or theCol < 1 or theCol > 3 void SetValue(const int theRow, const int theCol, const double theValue) { Standard_OutOfRange_Raise_if(theRow < 1 || theRow > 3 || theCol < 1 || theCol > 3, " "); myMat[theRow - 1][theCol - 1] = theValue; } //! Returns the column of theCol index. //! Raises OutOfRange if theCol < 1 or theCol > 3 Standard_EXPORT gp_XYZ Column(const int theCol) const; //! Computes the determinant of the matrix. constexpr double Determinant() const noexcept { const double a00 = myMat[0][0], a01 = myMat[0][1], a02 = myMat[0][2]; const double a10 = myMat[1][0], a11 = myMat[1][1], a12 = myMat[1][2]; const double a20 = myMat[2][0], a21 = myMat[2][1], a22 = myMat[2][2]; // clang-format off return a00 * (a11 * a22 - a21 * a12) - a01 * (a10 * a22 - a20 * a12) + a02 * (a10 * a21 - a20 * a11); // clang-format on } //! Returns the main diagonal of the matrix. Standard_EXPORT gp_XYZ Diagonal() const; //! returns the row of theRow index. //! Raises OutOfRange if theRow < 1 or theRow > 3 Standard_EXPORT gp_XYZ Row(const int theRow) const; //! Returns the coefficient of range (theRow, theCol) //! Raises OutOfRange if theRow < 1 or theRow > 3 or theCol < 1 or theCol > 3 const double& Value(const int theRow, const int theCol) const { Standard_OutOfRange_Raise_if(theRow < 1 || theRow > 3 || theCol < 1 || theCol > 3, " "); return myMat[theRow - 1][theCol - 1]; } const double& operator()(const int theRow, const int theCol) const { return Value(theRow, theCol); } //! Returns the coefficient of range (theRow, theCol) //! Raises OutOfRange if theRow < 1 or theRow > 3 or theCol < 1 or theCol > 3 double& ChangeValue(const int theRow, const int theCol) { Standard_OutOfRange_Raise_if(theRow < 1 || theRow > 3 || theCol < 1 || theCol > 3, " "); return myMat[theRow - 1][theCol - 1]; } double& operator()(const int theRow, const int theCol) { return ChangeValue(theRow, theCol); } //! The Gauss LU decomposition is used to invert the matrix //! (see Math package) so the matrix is considered as singular if //! the largest pivot found is lower or equal to Resolution from gp. constexpr bool IsSingular() const noexcept { // Pour etre sur que Gauss va fonctionner, il faut faire Gauss ... const double aDet = Determinant(); return (aDet < 0.0 ? -aDet : aDet) <= gp::Resolution(); } constexpr void Add(const gp_Mat& theOther) noexcept; constexpr void operator+=(const gp_Mat& theOther) noexcept { Add(theOther); } //! Computes the sum of this matrix and //! the matrix theOther for each coefficient of the matrix : //! .Coef(i,j) + .Coef(i,j) [[nodiscard]] constexpr gp_Mat Added(const gp_Mat& theOther) const noexcept; [[nodiscard]] constexpr gp_Mat operator+(const gp_Mat& theOther) const noexcept { return Added(theOther); } constexpr void Divide(const double theScalar); constexpr void operator/=(const double theScalar) { Divide(theScalar); } //! Divides all the coefficients of the matrix by Scalar [[nodiscard]] constexpr gp_Mat Divided(const double theScalar) const; [[nodiscard]] constexpr gp_Mat operator/(const double theScalar) const { return Divided(theScalar); } Standard_EXPORT void Invert(); //! Inverses the matrix and raises if the matrix is singular. //! - Invert assigns the result to this matrix, while //! - Inverted creates a new one. //! Warning //! The Gauss LU decomposition is used to invert the matrix. //! Consequently, the matrix is considered as singular if the //! largest pivot found is less than or equal to gp::Resolution(). //! Exceptions //! Standard_ConstructionError if this matrix is singular, //! and therefore cannot be inverted. [[nodiscard]] Standard_EXPORT gp_Mat Inverted() const; //! Computes the product of two matrices * [[nodiscard]] constexpr gp_Mat Multiplied(const gp_Mat& theOther) const noexcept { gp_Mat aNewMat = *this; aNewMat.Multiply(theOther); return aNewMat; } [[nodiscard]] constexpr gp_Mat operator*(const gp_Mat& theOther) const noexcept { return Multiplied(theOther); } //! Computes the product of two matrices = * . constexpr void Multiply(const gp_Mat& theOther) noexcept; constexpr void operator*=(const gp_Mat& theOther) noexcept { Multiply(theOther); } constexpr void PreMultiply(const gp_Mat& theOther) noexcept; [[nodiscard]] constexpr gp_Mat Multiplied(const double theScalar) const noexcept; [[nodiscard]] constexpr gp_Mat operator*(const double theScalar) const noexcept { return Multiplied(theScalar); } //! Multiplies all the coefficients of the matrix by Scalar constexpr void Multiply(const double theScalar) noexcept; constexpr void operator*=(const double theScalar) noexcept { Multiply(theScalar); } Standard_EXPORT void Power(const int N); //! Computes = * * .......* , theN time. //! if theN = 0 = Identity //! if theN < 0 = .Invert() *...........* .Invert(). //! If theN < 0 an exception will be raised if the matrix is not //! inversible [[nodiscard]] gp_Mat Powered(const int theN) const { gp_Mat aMatN = *this; aMatN.Power(theN); return aMatN; } constexpr void Subtract(const gp_Mat& theOther) noexcept; constexpr void operator-=(const gp_Mat& theOther) noexcept { Subtract(theOther); } //! cOmputes for each coefficient of the matrix : //! .Coef(i,j) - .Coef(i,j) [[nodiscard]] constexpr gp_Mat Subtracted(const gp_Mat& theOther) const noexcept; [[nodiscard]] constexpr gp_Mat operator-(const gp_Mat& theOther) const noexcept { return Subtracted(theOther); } void Transpose(); //! Transposes the matrix. A(j, i) -> A (i, j) [[nodiscard]] gp_Mat Transposed() const { gp_Mat aNewMat = *this; aNewMat.Transpose(); return aNewMat; } //! Dumps the content of me into the stream Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const; friend class gp_XYZ; friend class gp_Trsf; friend class gp_GTrsf; private: double myMat[3][3]; }; //================================================================================================= inline constexpr gp_Mat::gp_Mat(const double theA11, const double theA12, const double theA13, const double theA21, const double theA22, const double theA23, const double theA31, const double theA32, const double theA33) noexcept : myMat{{theA11, theA12, theA13}, {theA21, theA22, theA23}, {theA31, theA32, theA33}} { } //================================================================================================= inline constexpr void gp_Mat::Add(const gp_Mat& theOther) noexcept { myMat[0][0] += theOther.myMat[0][0]; myMat[0][1] += theOther.myMat[0][1]; myMat[0][2] += theOther.myMat[0][2]; myMat[1][0] += theOther.myMat[1][0]; myMat[1][1] += theOther.myMat[1][1]; myMat[1][2] += theOther.myMat[1][2]; myMat[2][0] += theOther.myMat[2][0]; myMat[2][1] += theOther.myMat[2][1]; myMat[2][2] += theOther.myMat[2][2]; } //================================================================================================= inline constexpr gp_Mat gp_Mat::Added(const gp_Mat& theOther) const noexcept { gp_Mat aNewMat(*this); aNewMat.Add(theOther); return aNewMat; } //================================================================================================= inline constexpr void gp_Mat::Divide(const double theScalar) { Standard_ConstructionError_Raise_if((theScalar < 0.0 ? -theScalar : theScalar) <= gp::Resolution(), "gp_Mat : Divide by 0"); const double anUnSurScalar = 1.0 / theScalar; myMat[0][0] *= anUnSurScalar; myMat[0][1] *= anUnSurScalar; myMat[0][2] *= anUnSurScalar; myMat[1][0] *= anUnSurScalar; myMat[1][1] *= anUnSurScalar; myMat[1][2] *= anUnSurScalar; myMat[2][0] *= anUnSurScalar; myMat[2][1] *= anUnSurScalar; myMat[2][2] *= anUnSurScalar; } //================================================================================================= inline constexpr gp_Mat gp_Mat::Divided(const double theScalar) const { gp_Mat aNewMat(*this); aNewMat.Divide(theScalar); return aNewMat; } //================================================================================================= inline constexpr void gp_Mat::Multiply(const gp_Mat& theOther) noexcept { const double aT00 = myMat[0][0] * theOther.myMat[0][0] + myMat[0][1] * theOther.myMat[1][0] + myMat[0][2] * theOther.myMat[2][0]; const double aT01 = myMat[0][0] * theOther.myMat[0][1] + myMat[0][1] * theOther.myMat[1][1] + myMat[0][2] * theOther.myMat[2][1]; const double aT02 = myMat[0][0] * theOther.myMat[0][2] + myMat[0][1] * theOther.myMat[1][2] + myMat[0][2] * theOther.myMat[2][2]; const double aT10 = myMat[1][0] * theOther.myMat[0][0] + myMat[1][1] * theOther.myMat[1][0] + myMat[1][2] * theOther.myMat[2][0]; const double aT11 = myMat[1][0] * theOther.myMat[0][1] + myMat[1][1] * theOther.myMat[1][1] + myMat[1][2] * theOther.myMat[2][1]; const double aT12 = myMat[1][0] * theOther.myMat[0][2] + myMat[1][1] * theOther.myMat[1][2] + myMat[1][2] * theOther.myMat[2][2]; const double aT20 = myMat[2][0] * theOther.myMat[0][0] + myMat[2][1] * theOther.myMat[1][0] + myMat[2][2] * theOther.myMat[2][0]; const double aT21 = myMat[2][0] * theOther.myMat[0][1] + myMat[2][1] * theOther.myMat[1][1] + myMat[2][2] * theOther.myMat[2][1]; const double aT22 = myMat[2][0] * theOther.myMat[0][2] + myMat[2][1] * theOther.myMat[1][2] + myMat[2][2] * theOther.myMat[2][2]; myMat[0][0] = aT00; myMat[0][1] = aT01; myMat[0][2] = aT02; myMat[1][0] = aT10; myMat[1][1] = aT11; myMat[1][2] = aT12; myMat[2][0] = aT20; myMat[2][1] = aT21; myMat[2][2] = aT22; } //================================================================================================= inline constexpr void gp_Mat::PreMultiply(const gp_Mat& theOther) noexcept { const double aT00 = theOther.myMat[0][0] * myMat[0][0] + theOther.myMat[0][1] * myMat[1][0] + theOther.myMat[0][2] * myMat[2][0]; const double aT01 = theOther.myMat[0][0] * myMat[0][1] + theOther.myMat[0][1] * myMat[1][1] + theOther.myMat[0][2] * myMat[2][1]; const double aT02 = theOther.myMat[0][0] * myMat[0][2] + theOther.myMat[0][1] * myMat[1][2] + theOther.myMat[0][2] * myMat[2][2]; const double aT10 = theOther.myMat[1][0] * myMat[0][0] + theOther.myMat[1][1] * myMat[1][0] + theOther.myMat[1][2] * myMat[2][0]; const double aT11 = theOther.myMat[1][0] * myMat[0][1] + theOther.myMat[1][1] * myMat[1][1] + theOther.myMat[1][2] * myMat[2][1]; const double aT12 = theOther.myMat[1][0] * myMat[0][2] + theOther.myMat[1][1] * myMat[1][2] + theOther.myMat[1][2] * myMat[2][2]; const double aT20 = theOther.myMat[2][0] * myMat[0][0] + theOther.myMat[2][1] * myMat[1][0] + theOther.myMat[2][2] * myMat[2][0]; const double aT21 = theOther.myMat[2][0] * myMat[0][1] + theOther.myMat[2][1] * myMat[1][1] + theOther.myMat[2][2] * myMat[2][1]; const double aT22 = theOther.myMat[2][0] * myMat[0][2] + theOther.myMat[2][1] * myMat[1][2] + theOther.myMat[2][2] * myMat[2][2]; myMat[0][0] = aT00; myMat[0][1] = aT01; myMat[0][2] = aT02; myMat[1][0] = aT10; myMat[1][1] = aT11; myMat[1][2] = aT12; myMat[2][0] = aT20; myMat[2][1] = aT21; myMat[2][2] = aT22; } //================================================================================================= inline constexpr gp_Mat gp_Mat::Multiplied(const double theScalar) const noexcept { gp_Mat aNewMat(*this); aNewMat.Multiply(theScalar); return aNewMat; } //================================================================================================= inline constexpr void gp_Mat::Multiply(const double theScalar) noexcept { myMat[0][0] *= theScalar; myMat[0][1] *= theScalar; myMat[0][2] *= theScalar; myMat[1][0] *= theScalar; myMat[1][1] *= theScalar; myMat[1][2] *= theScalar; myMat[2][0] *= theScalar; myMat[2][1] *= theScalar; myMat[2][2] *= theScalar; } //================================================================================================= inline constexpr void gp_Mat::Subtract(const gp_Mat& theOther) noexcept { myMat[0][0] -= theOther.myMat[0][0]; myMat[0][1] -= theOther.myMat[0][1]; myMat[0][2] -= theOther.myMat[0][2]; myMat[1][0] -= theOther.myMat[1][0]; myMat[1][1] -= theOther.myMat[1][1]; myMat[1][2] -= theOther.myMat[1][2]; myMat[2][0] -= theOther.myMat[2][0]; myMat[2][1] -= theOther.myMat[2][1]; myMat[2][2] -= theOther.myMat[2][2]; } //================================================================================================= inline constexpr gp_Mat gp_Mat::Subtracted(const gp_Mat& theOther) const noexcept { gp_Mat aNewMat(*this); aNewMat.Subtract(theOther); return aNewMat; } //================================================================================================= // On macOS 10.13.6 with XCode 9.4.1 the compiler has a bug leading to // generation of invalid code when method gp_Mat::Transpose() is called // for a matrix which is when applied to vector; it looks like vector // is transformed before the matrix is actually transposed; see #29978. // To avoid this, we disable compiler optimization here. #if defined(__APPLE__) && (__apple_build_version__ > 9020000) __attribute__((optnone)) #endif inline void gp_Mat::Transpose() { std::swap(myMat[0][1], myMat[1][0]); std::swap(myMat[0][2], myMat[2][0]); std::swap(myMat[1][2], myMat[2][1]); } //======================================================================= // function : operator* // purpose : //======================================================================= inline constexpr gp_Mat operator*(const double theScalar, const gp_Mat& theMat3D) noexcept { return theMat3D.Multiplied(theScalar); } #endif // _gp_Mat_HeaderFile