Game Physics Cookbook
上QQ阅读APP看书,第一时间看更新

Transpose

The transpose of matrix M, written as Transpose is a matrix in which every element i, j equals the element j, i of the original matrix. The transpose of a matrix can be acquired by reflecting the matrix over its main diagonal, writing the rows of M as the columns of Transpose, or by writing the columns of M as the rows of Transpose. We can express the transpose for each component of a matrix with the following equation:

Transpose

The transpose operation replaces the rows of a matrix with its columns:

Transpose Transpose

Getting ready

We're going to create a non-nested loop that serves as a generic Transpose function. This function will be able to transpose matrices of any dimension. We're then going to create Transpose functions specific to 2 X 2, 3 X 3, and 4 X 4 matrices. These more specific functions are going to call the generic Transpose with the appropriate arguments.

How to do it…

Follow these steps to implement a generic transpose function and transpose functions for two, three and four dimensional square matrices:

  1. Add the declarations for all of the Transpose function to matrices.h:
    void Transpose(const float *srcMat, float *dstMat, 
       int srcRows, int srcCols);
    mat2 Transpose(const mat2& matrix);
    mat3 Transpose(const mat3& matrix);
    mat4 Transpose(const mat4& matrix);
  2. Create a new file, matrices.cpp. In this file, include the cmath, cfloat, and matrices.h headers. Also, include a copy of the CMP macro we used in vectors.cpp:
    #include "matrices.h"
    #include <cmath>
    #include <cfloat>
    
    #define CMP(x, y)                               \
       (fabsf((x) – (y)) <= FLT_EPSILON * \
       fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y))))
  3. Implement the generic transpose function in matrices.cpp:
    void Transpose(const float *srcMat, float *dstMat, 
       int srcRows, int srcCols) {
       for (int i = 0; i < srcRows * srcCols; i++) {
          int row = i / srcRows;
          int ccl = i % srcRows;
          dstMat[i] = srcMat[srcCols * col + row];
       }
    }
  4. Using the generic Transpose function, implement Transpose for 2 X 2, 3 X 3, and 4 X 4 matrices in matrices.cpp:
    mat2 Transpose(const mat2& matrix) {
        mat2 result;
        Transpose(matrix.asArray, result.asArray, 2, 2);
        return result;
    }
    
    mat3 Transpose(const mat3& matrix) {
        mat3 result;
        Transpose(matrix.asArray, result.asArray, 3, 3);
        return result;
    }
    
    mat4 Transpose(const mat4& matrix) {
        mat4 result;
        Transpose(matrix.asArray, result.asArray, 4, 4);
        return result;
    }

How it works…

Let's explore how the generic version of Transpose works by examining how a single element is transposed. Assume we have the following 4 X 4 matrix:

How it works…

We're going to find the transpose of the element in row 3, column 4; it has the value L. If we access the matrix as an array, the linear index of L is 11. Let's explore how the generic Transpose loop works when i == 11.

First, the values of row and col are calculated. To calculate the row of the element: row = i / srcRows, substitute 11 for i, this becomes row = 11 / 4. C++ integer division truncates the result towards 0, therefore row = 2. Remember the array is indexed starting at 0 not 1, meaning the row at index 2 is actually the third row. The column is calculated using the modulo operator col = i % srcRows, substituting the variables becomes col = 11 % 4. The result of this operation is 3. Again, the column at index 3 is actually the 4th column, and this is the expected behavior.

We index the source array using [srcCols * col + row], substituting the variables, this becomes [4 * 3 + 2]. The result is index 14. The element in the original matrix at index 14 is element O, the transpose of L.

To index the original element, L, we would change the index calculation to [srcCols * row + col]. To access the transpose of the element, all we had to do was switch the row and col variables.