<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. BIM Math
  3. Matrices and transforms
All lessons in this course

Lesson 24 of 44 14 minAdvanced

Matrices and matrix multiplication

A matrix is a grid of numbers that moves every point of the plane or of space at once. Read its columns as “where the axes go”, multiply matrices row by column, and use the determinant to see what happens to areas.

Every time a BIM tool moves, rotates, scales or mirrors something, it multiplies coordinates by a matrix: a rectangular grid of numbers. One matrix holds the whole recipe, so the same few lines of code can place a door, rotate a building footprint or turn model coordinates into screen pixels.

A 2×2 matrix acts on 2D points. Pick a preset or move the four sliders, and watch the grid, the “F” and the point P all move together.

Interactive

A 2×2 matrix moves the whole plane

Move the sliders or pick a preset, and drag the point P. The green arrow is the first column, the purple one the second.

P′P
M1−0.5
0.51
P(3, −2)
x′ = a·x + c·y4.00
y′ = b·x + d·y−0.50
det = ad − bc1.250
The X axis lands on (1, 0.5) and the Y axis on (−0.5, 1): the two columns. Every area is multiplied by det = 1.250; the unit square becomes the purple parallelogram.

A matrix times a point

Write the matrix with entries a, c on the top row and b, d on the bottom row, and the point P = (x, y) as a column. Then x′ = a·x + c·y and y′ = b·x + d·y: each output is one row of the matrix dotted with the point.

There is a more useful way to read the same sum: M·P = x × (first column) + y × (second column). The point (1, 0) lands on the first column and (0, 1) on the second. So the columns are where the X and Y axes go, and every other point follows, because it is a mix of the two axes. That is what the green and purple arrows in the widget show, and it is how you can write down a matrix just by thinking about where the axes should end up.

TransformFirst column (X goes to)Second column (Y goes to)det
Identity (no change)(1, 0)(0, 1)1
Scale by s(s, 0)(0, s)s²
Stretch X by 2(2, 0)(0, 1)2
Shear: Y leans over by 0.8(1, 0)(0.8, 1)1
Rotate by θ(cos θ, sin θ)(−sin θ, cos θ)1
Mirror in the Y axis(−1, 0)(0, 1)−1

Multiplying two matrices

To do one transform and then another, multiply their matrices. Entry (i, j) of A·B is row i of A dotted with column j of B. The sizes must fit: an m×n matrix can multiply an n×p one, and the result is m×p. A point written as a column is just an n×1 matrix, so the same function handles both.

MatrixMultiply.cs
double[,] rotate90 = { { 0, -1 }, { 1, 0 } };double[,] stretchX = { { 2, 0 }, { 0, 1 } }; Print("Stretch, then rotate (R * S)", Multiply(rotate90, stretchX));Print("Rotate, then stretch (S * R)", Multiply(stretchX, rotate90)); double[,] p = { { 1 }, { 1 } };          // the point (1, 1) as a 2x1 columnPrint("(R * S) * p", Multiply(Multiply(rotate90, stretchX), p)); static double[,] Multiply(double[,] a, double[,] b){    int n = a.GetLength(0), m = a.GetLength(1), q = b.GetLength(1);    if (b.GetLength(0) != m)        throw new ArgumentException($"Cannot multiply {n}x{m} by {b.GetLength(0)}x{q}");    var c = new double[n, q];    for (int i = 0; i < n; i++)        for (int j = 0; j < q; j++)            for (int k = 0; k < m; k++)                c[i, j] += a[i, k] * b[k, j];      // row i of a, dotted with column j of b    return c;} static void Print(string title, double[,] m){    Console.WriteLine(title + ":");    for (int i = 0; i < m.GetLength(0); i++)    {        var row = new string[m.GetLength(1)];        for (int j = 0; j < row.Length; j++) row[j] = m[i, j].ToString("0.###").PadLeft(3);        Console.WriteLine("  [" + string.Join(" ", row) + " ]");    }}
Output
Stretch, then rotate (R * S):
  [  0  -1 ]
  [  2   0 ]
Rotate, then stretch (S * R):
  [  0  -2 ]
  [  1   0 ]
(R * S) * p:
  [ -1 ]
  [  2 ]

The two products are different matrices. Matrix multiplication is not commutative: A·B is usually not B·A, just as “stretch, then rotate” is not “rotate, then stretch”. It is, however, associative: (A·B)·C = A·(B·C). That is what lets a program multiply a long chain of transforms into one matrix once, then apply that single matrix to thousands of points.

The determinant

For a 2×2 matrix, det = a·d − b·c. It is the factor by which the matrix scales every area: the unit square becomes a parallelogram of area |det|, and every room, slab and hatch scales the same way. The sign carries meaning too:

  • det > 0: shapes keep their orientation. Rotations have det = 1, so they keep areas exactly.
  • det < 0: the transform includes a mirror. Outlines reverse their winding, and an “F” reads backwards.
  • det = 0: the plane is squashed onto a line (or a point). Areas become 0, and the matrix has no inverse: you cannot undo it.
ScaleArea.cs
var room = new V2[] { new(0, 0), new(6, 0), new(6, 4), new(0, 4) };var matrices = new (string Name, double A, double B, double C, double D)[]{    ("Scale x2", 2, 0, 0, 2),    ("Shear 0.5", 1, 0, 0.5, 1),    ("Mirror in Y", -1, 0, 0, 1),    ("Squash", 1, 0.5, 2, 1)}; Console.WriteLine($"Room: {Area(room)} m2");foreach (var (name, a, b, c, d) in matrices){    var moved = room.Select(p => new V2(a * p.X + c * p.Y, b * p.X + d * p.Y)).ToArray();    Console.WriteLine($"{name,-12} det {a * d - b * c,3}   signed area {Area(moved),4} m2");} static double Area(V2[] p){    double s = 0;    for (int i = 0; i < p.Length; i++)    {        V2 u = p[i], v = p[(i + 1) % p.Length];        s += u.X * v.Y - v.X * u.Y;    }    return s / 2;} readonly record struct V2(double X, double Y){    public static V2 operator +(V2 a, V2 b) => new(a.X + b.X, a.Y + b.Y);    public static V2 operator -(V2 a, V2 b) => new(a.X - b.X, a.Y - b.Y);    public static V2 operator *(V2 v, double k) => new(v.X * k, v.Y * k);    public double Length => Math.Sqrt(X * X + Y * Y);    static string F(double v) => Math.Abs(v) < 5e-4 ? "0" : v.ToString("0.###");    public override string ToString() => $"({F(X)}, {F(Y)})";}
Output
Room: 24 m2
Scale x2     det   4   signed area   96 m2
Shear 0.5    det   1   signed area   24 m2
Mirror in Y  det  -1   signed area  -24 m2
Squash       det   0   signed area    0 m2

Every signed area is exactly det × 24. The mirror gives −24: the same size, but the corners now run clockwise, which is the shoelace formula’s way of saying “mirrored”.

Quick check

A matrix has columns (0, 1) and (−1, 0). Where does the point (3, 0) go?

Quick check

A transform has det = −0.5. What does it do to a 10 m² room?

Practice

Write Det2 for a 2×2 matrix given as a, b, c, d (columns (a, b) and (c, d)), and use it to classify these: a 30° rotation, a 1:100 drawing scale (0.01 on the diagonal), a mirror in the X axis, the matrix with columns (1, 0.5) and (2, 1), and a shear with columns (1, 0) and (0.5, 1). Print whether each keeps areas, scales them, mirrors, or squashes.

Show a hint

Compare |det| with a small tolerance before you look at its sign, so that a squash is caught first.

Show the solution
Solution.cs
double c30 = Math.Cos(Math.PI / 6), s30 = Math.Sin(Math.PI / 6);var tests = new (string Name, double A, double B, double C, double D)[]{    ("Rotate 30", c30, s30, -s30, c30),    ("Drawing 1:100", 0.01, 0, 0, 0.01),    ("Mirror in X", 1, 0, 0, -1),    ("Columns (1,0.5) (2,1)", 1, 0.5, 2, 1),    ("Shear", 1, 0, 0.5, 1)}; foreach (var (name, a, b, c, d) in tests){    double det = Det2(a, b, c, d);    string kind =        Math.Abs(det) < 1e-9 ? "squashes onto a line, no inverse" :        det < 0 ? $"mirrors, areas x {Math.Abs(det):0.####}" :        Math.Abs(det - 1) < 1e-9 ? "keeps areas" :        $"scales areas by {det:0.####}";    Console.WriteLine($"{name}: {kind}");} static double Det2(double a, double b, double c, double d) => a * d - b * c;
Output
Rotate 30: keeps areas
Drawing 1:100: scales areas by 0.0001
Mirror in X: mirrors, areas x 1
Columns (1,0.5) (2,1): squashes onto a line, no inverse
Shear: keeps areas

Remember

  • A matrix times a point is a mix of its columns: the columns are where the axes go.
  • Entry (i, j) of A·B is row i of A dotted with column j of B; an m×n matrix multiplies an n×p one.
  • Matrix multiplication is associative but not commutative: A·B ≠ B·A in general.
  • In M·P the matrix nearest the point acts first.
  • The determinant is the area (or volume) factor: negative means mirrored, zero means squashed and not invertible.
0 of 44 lessons completed