Concepts

The Imath library emphasizes simplicity, ease of use, correctness and verifiability, performance, and breadth of adoption. Imath is not intended to be a comprehensive linear algebra or numerical analysis package.

Imath is not a substitute for Eigen! It’s not a full-featured linear algebra package, and it doesn’t represent vectors and matrices of arbitrary dimension. Its greatest utility is as a geometric data representation, primarily for 2D images and 3D scenes and coordinate transformations, along with an accompanying set of utility methods and functions.

Example

A basic program:

#include <Imath/ImathMatrix.h>
#include <Imath/ImathVec.h>
#include <iostream>
#include <cassert>

int
main()
{
    const Imath::V3f v (3.0f, 4.0f, 5.0f);
   
    Imath::M44f M;
    const Imath::V3f t(1.0f, 2.0f, 3.0f);
    M.translate (t);

    Imath::V3f p;
    M.multVecMatrix(v, p);

    std::cout << "What's your vector, Victor? " << p << std::endl;

    Imath::V3f vt = v + t;
    assert (p.equalWithAbsError(vt, 1e-6f));

    return 0;
}

Matrices Are Row-Major

Imath stores matrices in row-major layout, originally inspired by compatibility with OpenGL matrices.

A matrix described as:

\[\begin{split}\begin{bmatrix} m_{00} & m_{01} & m_{02} & m_{03} \\ m_{10} & m_{11} & m_{12} & m_{13} \\ m_{20} & m_{21} & m_{22} & m_{23} \\ m_{30} & m_{31} & m_{32} & m_{33} \\ \end{bmatrix}\end{split}\]

is laid out in memory as:

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

\(m_{00}\)

\(m_{01}\)

\(m_{02}\)

\(m_{03}\)

\(m_{10}\)

\(m_{11}\)

\(m_{12}\)

\(m_{13}\)

\(m_{20}\)

\(m_{21}\)

\(m_{22}\)

\(m_{23}\)

\(m_{30}\)

\(m_{31}\)

\(m_{32}\)

\(m_{33}\)

A matrix representing a homogeneous transform has a right-hand column of \(\begin{bmatrix} 0 & 0 & 0 & 1\end{bmatrix}\) and the translation component across the bottom row.

As a result, it is best to think of Imath vectors as row-vectors, and vector-matrix multiplication with the vector on the left and matrix on the right:

\[\begin{split}\begin{bmatrix} v_{0}' & v_{1}' & v_{2}' & 1' \end{bmatrix} = \begin{bmatrix} v_{0} & v_{1} & v_{2} & 1 \end{bmatrix} \begin{bmatrix} m_{00} & m_{01} & m_{02} & 0 \\ m_{10} & m_{11} & m_{12} & 0 \\ m_{20} & m_{21} & m_{22} & 0 \\ m_{30} & m_{31} & m_{32} & 1 \end{bmatrix}\end{split}\]

This further implies that you should interpret local transformations as pre-multiplication:

M44f M;
M.translate (tx, ty, tz);
m.rotate (r, 0, 0);
m.scale (s);
\[\begin{split}\begin{bmatrix} m_{00} & m_{01} & m_{02} & m_{03} \\ m_{10} & m_{11} & m_{12} & m_{13} \\ m_{20} & m_{21} & m_{22} & m_{23} \\ m_{30} & m_{31} & m_{32} & m_{33} \\ \end{bmatrix} = \begin{bmatrix} s & 0 & 0 & 0 \\ 0 & s & 0 & 0 \\ 0 & 0 & s & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(r) & \sin(r) & 0 \\ 0 & -\sin(r) & \cos(r) & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ tx & ty & tz & 1 \\ \end{bmatrix}\end{split}\]