/** * @file XTPMatrix.h * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ /** @cond */ #if !defined(__XTPMATRIX_H__) # define __XTPMATRIX_H__ /** @endcond */ # if _MSC_VER >= 1000 # pragma once # endif // _MSC_VER >= 1000 # include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" /** * @brief * Represents a matrix object built upon a continuos array of elements * and provides basic algorithms for it. */ template class CXTPMatrix { public: /** * @brief * Constructs a matrix object of the specified size where each element * is set to zero. If either side is equal to 0 then the matrix is * considered to be a valid empty matrix. * @param nWidth The width of the matrix. * @param nHeight The height of the matrix. */ CXTPMatrix(UINT nWidth, UINT nHeight); /** * @brief * Handles matrix deallocation. */ ~CXTPMatrix(); public: /** * @brief * Obtains the width of the matrix. * @return * The width of the matrix. * @see * GetHeight */ UINT GetWidth() const; /** * @brief * Obtains the height of the matrix. * @return * The height of the matrix. * @see * GetWidth */ UINT GetHeight() const; /** * @brief * Obtains a point to the first element of the continuous array * upon which the matrix is built. * @return * The value of the pointer of the first element in the array * or NULL if matrix is empty. */ T* GetData(); /** * @brief * Obtains a point to the first element of the continuous array * upon which the matrix is built. * @return * The value of the pointer of the first element in the array * or NULL if matrix is empty. */ const T* GetData() const; /** * @brief * Clones the matrix. * @return * A pointer to the new cloned matrix object. The caller is responsible * for releasing resources using delete operator. */ CXTPMatrix* Clone() const; /** * @brief * Compares the current matrix to the matrix oject specified. * @param m A matrix to compare to. * @return * TRUE if the dimensions and all emlements of both matrices are identical. */ BOOL Equals(const CXTPMatrix& m) const; /** * @brief * Obtains an element value at the specified location. * @param nCol Zero-based column index. * @param nRow Zero-based row index. * @return * Element value at the specified location. * @see * SetAt */ T GetAt(UINT nCol, UINT nRow) const; /** * @brief * Sets element value at the specified location. * @param nCol Zero-based column index. * @param nRow Zero-based row index. * @param value A new element value. * @see * GetAt */ void SetAt(UINT nCol, UINT nRow, T value); /** * @brief * Makes the current matrix identical to the matrix provided. * @param m A matrix object to make the current matrix identical to. */ void Set(const CXTPMatrix& m); /** * @brief * Sets all matrix elements to 0. * @see * SetIdentity */ void SetZero(); /** * @brief * Make the current matrix an identity matrix, i.e. all elements * are set to 0 and the main diagonal elements are set to 1. Requires * the matrix to be a square matrix. * @see * SetZero */ void SetIdentity(); /** * @brief * Adds the matrix provided to the current matrix. Both matrixes * have to be of the same size. * @param m A matrix to add to the current matrix. * @see * Subtract, Multiply, Rotate, Transpose */ void Add(const CXTPMatrix& m); /** * @brief * Subtracts the matrix provided from the current matrix. Both matrixes * have to be of the same size. * @param m A matrix to subtract from the current matrix. * @see * Add, Multiply, Rotate, Transpose */ void Subtract(const CXTPMatrix& m); /** * @brief * Rotates 4x4 matrix using quaternion parameters. * @param xQuat X coordinate of the rotation vector. * @param yQuat Y coordinate of the rotation vector. * @param zQuat Z coordinate of the rotation vector. * @param wQuat Rotation angle. * @see * Add, Subtract, Multiply, Transpose */ void Rotate(T xQuat, T yQuat, T zQuat, T wQuat); /** * @brief * Multiplies the current matrix of size MxN to the provided matrix of size LxM. * The current matrix is on the left hand side of the multiplication expression. * @param m A matrix to be multiplied with. A caller is responsible for releasing * allocation resources using delete operator. * @return * A new matrix of size LxN which contains the result of matrix multiplication. * @see * Add, Subtract, Transpose, Rotate */ CXTPMatrix* Multiply(const CXTPMatrix& m) const; /** * @brief * Creates a transposed matrix, i.e. rows and columns are swapped. * @return * A new transposed matrix object. A caller is responsible for releasing * allocation resources using delete operator. * @see * Add, Subtract, Multiply, Rotate */ CXTPMatrix* Transpose() const; private: CXTPMatrix(const CXTPMatrix&); /**< non-copyable */ CXTPMatrix& operator=(const CXTPMatrix&); /**< non-copyable */ const UINT m_nWidth; const UINT m_nHeight; T* m_pData; }; template AFX_INLINE CXTPMatrix::CXTPMatrix(UINT nWidth, UINT nHeight) : m_nWidth(nWidth) , m_nHeight(nHeight) { if (0 < m_nWidth && 0 < m_nHeight) { m_pData = new T[m_nWidth * m_nHeight]; SetZero(); } else { m_pData = NULL; } } template AFX_INLINE CXTPMatrix::~CXTPMatrix() { if (NULL != m_pData) { delete[] m_pData; } } template AFX_INLINE UINT CXTPMatrix::GetWidth() const { return m_nWidth; } template AFX_INLINE UINT CXTPMatrix::GetHeight() const { return m_nHeight; } template AFX_INLINE T* CXTPMatrix::GetData() { return m_pData; } template AFX_INLINE const T* CXTPMatrix::GetData() const { return m_pData; } template AFX_INLINE CXTPMatrix* CXTPMatrix::Clone() const { CXTPMatrix* pClone = new CXTPMatrix(m_nWidth, m_nHeight); for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { pClone->GetData()[i] = m_pData[i]; } return pClone; } template AFX_INLINE BOOL CXTPMatrix::Equals(const CXTPMatrix& m) const { BOOL bEquals = FALSE; if (GetWidth() == m.GetWidth() && GetHeight() == m.GetHeight()) { bEquals = TRUE; for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { if (m_pData[i] != m.GetData()[i]) { bEquals = FALSE; break; } } } return bEquals; } template AFX_INLINE T CXTPMatrix::GetAt(UINT nCol, UINT nRow) const { _ASSERTE(nCol < m_nWidth); _ASSERTE(nRow < m_nHeight); UINT nIndex = nRow * m_nWidth + nCol; return m_pData[nIndex]; } template AFX_INLINE void CXTPMatrix::SetAt(UINT nCol, UINT nRow, T value) { _ASSERTE(nCol < m_nWidth); _ASSERTE(nRow < m_nHeight); UINT nIndex = nRow * m_nWidth + nCol; m_pData[nIndex] = value; } template AFX_INLINE void CXTPMatrix::Set(const CXTPMatrix& m) { if (GetWidth() == m.GetWidth() && GetHeight() == m.GetHeight()) { for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { m_pData[i] = m.GetData()[i]; } } else { _ASSERTE(!"Matrices must have the same size"); } } template AFX_INLINE void CXTPMatrix::SetZero() { for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { m_pData[i] = T(); } } template AFX_INLINE void CXTPMatrix::SetIdentity() { if (m_nWidth == m_nHeight) { SetZero(); for (UINT i = 0; i < m_nWidth; ++i) { SetAt(i, i, T(1)); } } else { _ASSERTE(!"Only square matrix with odd sizes can be set to identity"); } } template AFX_INLINE void CXTPMatrix::Add(const CXTPMatrix& m) { if (GetWidth() == m.GetWidth() && GetHeight() == m.GetHeight()) { for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { m_pData[i] += m.GetData()[i]; } } else { _ASSERTE(!"Matrices must have the same size"); } } template AFX_INLINE void CXTPMatrix::Subtract(const CXTPMatrix& m) { if (GetWidth() == m.GetWidth() && GetHeight() == m.GetHeight()) { for (UINT i = 0; i < (m_nWidth * m_nHeight); ++i) { m_pData[i] -= m.GetData()[i]; } } else { _ASSERTE(!"Matrices must have the same size"); } } template AFX_INLINE void CXTPMatrix::Rotate(T xQuat, T yQuat, T zQuat, T wQuat) { if (4 == m_nWidth && 4 == m_nHeight) { T n = (xQuat * xQuat) + (yQuat * yQuat) + (zQuat * zQuat) + (wQuat * wQuat); T s = (T(0) < n) ? (T(2) / n) : T(0); T xs = xQuat * s; T ys = yQuat * s; T zs = zQuat * s; T wx = wQuat * xs; T wy = wQuat * ys; T wz = wQuat * zs; T xx = xQuat * xs; T xy = xQuat * ys; T xz = xQuat * zs; T yy = yQuat * ys; T yz = yQuat * zs; T zz = zQuat * zs; SetAt(0, 0, T(1) - (yy + zz)); SetAt(0, 1, xy - wz); SetAt(0, 2, xz + wy); SetAt(0, 3, T(0)); SetAt(1, 0, xy + wz); SetAt(1, 1, T(1) - (xx + zz)); SetAt(1, 2, yz - wx); SetAt(1, 3, T(0)); SetAt(2, 0, xz - wy); SetAt(2, 1, yz + wx); SetAt(2, 2, T(1) - (xx + yy)); SetAt(2, 3, T(0)); SetAt(3, 0, T(0)); SetAt(3, 1, T(0)); SetAt(3, 2, T(0)); SetAt(3, 3, T(1)); } else { _ASSERTE(!"Only 4x4 matrix can be rotated using a quaternion"); } } template AFX_INLINE CXTPMatrix* CXTPMatrix::Multiply(const CXTPMatrix& m) const { CXTPMatrix* pResult = NULL; if (GetWidth() == m.GetHeight()) { pResult = new CXTPMatrix(m.GetWidth(), GetHeight()); for (UINT nRow = 0; nRow < GetHeight(); ++nRow) { for (UINT nCol = 0; nCol < m.GetWidth(); ++nCol) { T& value = pResult->GetData()[nCol * GetHeight() + nRow]; value = T(0); for (UINT nRowLeft = 0; nRowLeft < GetWidth(); ++nRowLeft) { value += GetData()[nRowLeft * GetHeight() + nRow] * m.GetData()[nCol * GetWidth() + nRowLeft]; } } } } else { _ASSERTE(!"Matrices cannot be multiplied"); } return pResult; } template AFX_INLINE CXTPMatrix* CXTPMatrix::Transpose() const { CXTPMatrix* pResult = new CXTPMatrix(GetHeight(), GetWidth()); for (UINT nRow = 0; nRow < GetHeight(); ++nRow) { for (UINT nCol = 0; nCol < GetWidth(); ++nCol) { pResult->SetAt(nRow, nCol, GetAt(nCol, nRow)); } } return pResult; } # include "Common/Base/Diagnostic/XTPEnableNoisyWarnings.h" /** @cond */ #endif //#if !defined(__XTPMATRIX_H__) /** @endcond */