// 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_GTrsf_HeaderFile #define _gp_GTrsf_HeaderFile #include "gp_Ax1.hxx" #include "gp_Ax2.hxx" #include "gp_Mat.hxx" #include "gp_Trsf.hxx" #include "gp_TrsfForm.hxx" #include "gp_XYZ.hxx" #include "Standard_ConstructionError.hxx" #include "Standard_OutOfRange.hxx" // Avoid possible conflict with SetForm macro defined by windows.h #ifdef SetForm #undef SetForm #endif //! Defines a non-persistent transformation in 3D space. //! This transformation is a general transformation. //! It can be a gp_Trsf, an affinity, or you can define //! your own transformation giving the matrix of transformation. //! //! With a gp_GTrsf you can transform only a triplet of coordinates gp_XYZ. //! It is not possible to transform other geometric objects //! because these transformations can change the nature of non-elementary geometric objects. //! The transformation gp_GTrsf can be represented as follow: //! @code //! V1 V2 V3 T XYZ XYZ //! | a11 a12 a13 a14 | | x | | x'| //! | a21 a22 a23 a24 | | y | | y'| //! | a31 a32 a33 a34 | | z | = | z'| //! | 0 0 0 1 | | 1 | | 1 | //! @endcode //! where {V1, V2, V3} define the vectorial part of the //! transformation and T defines the translation part of the transformation. //! Warning //! A gp_GTrsf transformation is only applicable to coordinates. //! Be careful if you apply such a transformation to all points of a geometric object, //! as this can change the nature of the object and thus render it incoherent! //! Typically, a circle is transformed into an ellipse by an affinity transformation. //! To avoid modifying the nature of an object, use a gp_Trsf transformation instead, //! as objects of this class respect the nature of geometric objects. class gp_GTrsf { public: DEFINE_STANDARD_ALLOC //! Returns the Identity transformation. constexpr gp_GTrsf() noexcept : loc(0.0, 0.0, 0.0), shape(gp_Identity), scale(1.0) { matrix.SetScale(1.0); } //! Converts the gp_Trsf transformation theT into a //! general transformation, i.e. Returns a GTrsf with //! the same matrix of coefficients as the Trsf theT. gp_GTrsf(const gp_Trsf& theT) { shape = theT.Form(); matrix = theT.matrix; loc = theT.TranslationPart(); scale = theT.ScaleFactor(); } //! Creates a transformation based on the matrix theM and the //! vector theV where theM defines the vectorial part of //! the transformation, and V the translation part, or constexpr gp_GTrsf(const gp_Mat& theM, const gp_XYZ& theV) noexcept : matrix(theM), loc(theV), shape(gp_Other), scale(0.0) { } //! Changes this transformation into an affinity of ratio theRatio //! with respect to the axis theA1. //! Note: an affinity is a point-by-point transformation that //! transforms any point P into a point P' such that if H is //! the orthogonal projection of P on the axis theA1 or the //! plane A2, the vectors HP and HP' satisfy: //! HP' = theRatio * HP. void SetAffinity(const gp_Ax1& theA1, const double theRatio); //! Changes this transformation into an affinity of ratio theRatio //! with respect to the plane defined by the origin, the "X Direction" and //! the "Y Direction" of coordinate system theA2. //! Note: an affinity is a point-by-point transformation that //! transforms any point P into a point P' such that if H is //! the orthogonal projection of P on the axis A1 or the //! plane theA2, the vectors HP and HP' satisfy: //! HP' = theRatio * HP. void SetAffinity(const gp_Ax2& theA2, const double theRatio); //! Replaces the coefficient (theRow, theCol) of the matrix representing //! this transformation by theValue. Raises OutOfRange //! if theRow < 1 or theRow > 3 or theCol < 1 or theCol > 4 void SetValue(const int theRow, const int theCol, const double theValue); //! Replaces the vectorial part of this transformation by theMatrix. constexpr void SetVectorialPart(const gp_Mat& theMatrix) noexcept { matrix = theMatrix; shape = gp_Other; scale = 0.0; } //! Replaces the translation part of //! this transformation by the coordinates of the number triple theCoord. Standard_EXPORT void SetTranslationPart(const gp_XYZ& theCoord); //! Assigns the vectorial and translation parts of theT to this transformation. void SetTrsf(const gp_Trsf& theT) { shape = theT.shape; matrix = theT.matrix; loc = theT.loc; scale = theT.scale; } //! Returns true if the determinant of the vectorial part of //! this transformation is negative. constexpr bool IsNegative() const noexcept { return matrix.Determinant() < 0.0; } //! Returns true if this transformation is singular (and //! therefore, cannot be inverted). //! Note: The Gauss LU decomposition is used to invert the //! transformation matrix. Consequently, the transformation //! is considered as singular if the largest pivot found is less //! than or equal to gp::Resolution(). //! Warning //! If this transformation is singular, it cannot be inverted. constexpr bool IsSingular() const noexcept { return matrix.IsSingular(); } //! Returns the nature of the transformation. It can be an //! identity transformation, a rotation, a translation, a mirror //! transformation (relative to a point, an axis or a plane), a //! scaling transformation, a compound transformation or //! some other type of transformation. constexpr gp_TrsfForm Form() const noexcept { return shape; } //! verify and set the shape of the GTrsf Other or CompoundTrsf //! Ex : //! @code //! myGTrsf.SetValue(row1,col1,val1); //! myGTrsf.SetValue(row2,col2,val2); //! ... //! myGTrsf.SetForm(); //! @endcode Standard_EXPORT void SetForm(); //! Returns the translation part of the GTrsf. constexpr const gp_XYZ& TranslationPart() const noexcept { return loc; } //! Computes the vectorial part of the GTrsf. The returned Matrix //! is a 3*3 matrix. constexpr const gp_Mat& VectorialPart() const noexcept { return matrix; } //! Returns the coefficients of the global matrix of transformation. //! Raises OutOfRange if theRow < 1 or theRow > 3 or theCol < 1 or theCol > 4 constexpr double Value(const int theRow, const int theCol) const; double operator()(const int theRow, const int theCol) const { return Value(theRow, theCol); } Standard_EXPORT void Invert(); //! Computes the reverse transformation. //! Raises an exception if the matrix of the transformation //! is not inversible. [[nodiscard]] gp_GTrsf Inverted() const { gp_GTrsf aT = *this; aT.Invert(); return aT; } //! Computes the transformation composed from theT and . //! In a C++ implementation you can also write Tcomposed = * theT. //! Example : //! @code //! gp_GTrsf T1, T2, Tcomp; ............... //! //composition : //! Tcomp = T2.Multiplied(T1); // or (Tcomp = T2 * T1) //! // transformation of a point //! gp_XYZ P(10.,3.,4.); //! gp_XYZ P1(P); //! Tcomp.Transforms(P1); //using Tcomp //! gp_XYZ P2(P); //! T1.Transforms(P2); //using T1 then T2 //! T2.Transforms(P2); // P1 = P2 !!! //! @endcode [[nodiscard]] gp_GTrsf Multiplied(const gp_GTrsf& theT) const { gp_GTrsf aTres = *this; aTres.Multiply(theT); return aTres; } [[nodiscard]] gp_GTrsf operator*(const gp_GTrsf& theT) const { return Multiplied(theT); } //! Computes the transformation composed with and theT. //! = * theT Standard_EXPORT void Multiply(const gp_GTrsf& theT); void operator*=(const gp_GTrsf& theT) { Multiply(theT); } //! Computes the product of the transformation theT and this //! transformation and assigns the result to this transformation. //! this = theT * this Standard_EXPORT void PreMultiply(const gp_GTrsf& theT); Standard_EXPORT void Power(const int theN); //! Computes: //! - the product of this transformation multiplied by itself //! theN times, if theN is positive, or //! - the product of the inverse of this transformation //! multiplied by itself |theN| times, if theN is negative. //! If theN equals zero, the result is equal to the Identity //! transformation. //! I.e.: * * .......* , theN time. //! if theN =0 = Identity //! if theN < 0 = .Inverse() *...........* .Inverse(). //! //! Raises an exception if N < 0 and if the matrix of the //! transformation not inversible. [[nodiscard]] gp_GTrsf Powered(const int theN) const { gp_GTrsf aT = *this; aT.Power(theN); return aT; } constexpr void Transforms(gp_XYZ& theCoord) const noexcept; //! Transforms a triplet XYZ with a GTrsf. constexpr void Transforms(double& theX, double& theY, double& theZ) const noexcept; gp_Trsf Trsf() const; //! Convert transformation to 4x4 matrix. template void GetMat4(NCollection_Mat4& theMat) const { if (shape == gp_Identity) { theMat.InitIdentity(); return; } theMat.SetValue(0, 0, static_cast(Value(1, 1))); theMat.SetValue(0, 1, static_cast(Value(1, 2))); theMat.SetValue(0, 2, static_cast(Value(1, 3))); theMat.SetValue(0, 3, static_cast(Value(1, 4))); theMat.SetValue(1, 0, static_cast(Value(2, 1))); theMat.SetValue(1, 1, static_cast(Value(2, 2))); theMat.SetValue(1, 2, static_cast(Value(2, 3))); theMat.SetValue(1, 3, static_cast(Value(2, 4))); theMat.SetValue(2, 0, static_cast(Value(3, 1))); theMat.SetValue(2, 1, static_cast(Value(3, 2))); theMat.SetValue(2, 2, static_cast(Value(3, 3))); theMat.SetValue(2, 3, static_cast(Value(3, 4))); theMat.SetValue(3, 0, static_cast(0)); theMat.SetValue(3, 1, static_cast(0)); theMat.SetValue(3, 2, static_cast(0)); theMat.SetValue(3, 3, static_cast(1)); } //! Convert transformation from 4x4 matrix. template void SetMat4(const NCollection_Mat4& theMat) { shape = gp_Other; scale = 0.0; matrix.SetValue(1, 1, theMat.GetValue(0, 0)); matrix.SetValue(1, 2, theMat.GetValue(0, 1)); matrix.SetValue(1, 3, theMat.GetValue(0, 2)); matrix.SetValue(2, 1, theMat.GetValue(1, 0)); matrix.SetValue(2, 2, theMat.GetValue(1, 1)); matrix.SetValue(2, 3, theMat.GetValue(1, 2)); matrix.SetValue(3, 1, theMat.GetValue(2, 0)); matrix.SetValue(3, 2, theMat.GetValue(2, 1)); matrix.SetValue(3, 3, theMat.GetValue(2, 2)); loc.SetCoord(theMat.GetValue(0, 3), theMat.GetValue(1, 3), theMat.GetValue(2, 3)); } //! Dumps the content of me into the stream Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const; private: gp_Mat matrix; gp_XYZ loc; gp_TrsfForm shape; double scale; }; //================================================================================================= inline void gp_GTrsf::SetAffinity(const gp_Ax1& theA1, const double theRatio) { shape = gp_Other; scale = 0.0; matrix.SetDot(theA1.Direction().XYZ()); matrix.Multiply(1.0 - theRatio); matrix.SetDiagonal(matrix.Value(1, 1) + theRatio, matrix.Value(2, 2) + theRatio, matrix.Value(3, 3) + theRatio); loc = theA1.Location().XYZ(); loc.Reverse(); loc.Multiply(matrix); loc.Add(theA1.Location().XYZ()); } //================================================================================================= inline void gp_GTrsf::SetAffinity(const gp_Ax2& theA2, const double theRatio) { shape = gp_Other; scale = 0.0; matrix.SetDot(theA2.Direction().XYZ()); matrix.Multiply(theRatio - 1.); loc = theA2.Location().XYZ(); loc.Reverse(); loc.Multiply(matrix); matrix.SetDiagonal(matrix.Value(1, 1) + 1., matrix.Value(2, 2) + 1., matrix.Value(3, 3) + 1.); } //================================================================================================= inline void gp_GTrsf::SetValue(const int theRow, const int theCol, const double theValue) { Standard_OutOfRange_Raise_if(theRow < 1 || theRow > 3 || theCol < 1 || theCol > 4, " "); if (theCol == 4) { loc.SetCoord(theRow, theValue); if (shape == gp_Identity) { shape = gp_Translation; } return; } else { if (!(shape == gp_Other) && !(scale == 1.0)) { matrix.Multiply(scale); } matrix.SetValue(theRow, theCol, theValue); shape = gp_Other; scale = 0.0; return; } } //================================================================================================= inline constexpr double gp_GTrsf::Value(const int theRow, const int theCol) const { Standard_OutOfRange_Raise_if(theRow < 1 || theRow > 3 || theCol < 1 || theCol > 4, " "); if (theCol == 4) { return loc.Coord(theRow); } if (shape == gp_Other) { return matrix.myMat[theRow - 1][theCol - 1]; } return scale * matrix.myMat[theRow - 1][theCol - 1]; } //================================================================================================= inline constexpr void gp_GTrsf::Transforms(gp_XYZ& theCoord) const noexcept { theCoord.Multiply(matrix); if (!(shape == gp_Other) && !(scale == 1.0)) { theCoord.Multiply(scale); } theCoord.Add(loc); } //================================================================================================= inline constexpr void gp_GTrsf::Transforms(double& theX, double& theY, double& theZ) const noexcept { gp_XYZ aTriplet(theX, theY, theZ); aTriplet.Multiply(matrix); if (!(shape == gp_Other) && !(scale == 1.0)) { aTriplet.Multiply(scale); } aTriplet.Add(loc); aTriplet.Coord(theX, theY, theZ); } //================================================================================================= inline gp_Trsf gp_GTrsf::Trsf() const { if (Form() == gp_Other) { throw Standard_ConstructionError("gp_GTrsf::Trsf() - non-orthogonal GTrsf"); } gp_Trsf aT; aT.shape = shape; aT.scale = scale; aT.matrix = matrix; aT.loc = loc; return aT; } #endif // _gp_GTrsf_HeaderFile