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

Lesson 9 of 44 16 minBeginner

The dot product: angles, projection, facing

One multiplication tells you the angle between two directions, how far along a wall a point lies, and whether a face points towards the sun. The most useful line of code in geometry.

The dot product of two vectors multiplies matching components and adds the results. The answer is a single number, not a vector:

a · b = a.x·b.x + a.y·b.y + a.z·b.z

It is cheap (three multiplications and two additions), and it has a second, geometric meaning that makes it useful everywhere:

a · b = |a| |b| cos θ, where θ is the angle between a and b.

Interactive

The dot product: angle and shadow

Drag the tips of a and b. The green arrow is b’s shadow on a’s line; the shaded half is every direction with a positive dot product with a.

θab
a⟨4, 1⟩
b⟨2, 3.5⟩
a · b4×2 + 1×3.5
= 11.5
|a|, |b|4.12, 4.03
cos θ = a·b ÷ (|a||b|)0.692
θ46.2°
shadow b · â2.79
a · b = 11.5 > 0: the angle (46.2°) is under 90°, so b points into the same half as a. If a were a face normal and b the direction to the sun, the face would be lit.

The sign alone says a lot

a · bAngleMeaning
positiveless than 90°roughly the same direction
zeroexactly 90°perpendicular
negativemore than 90°roughly opposite directions

You do not even need the lengths for this: the lengths are always positive, so the sign of a · b is the sign of cos θ. That makes “is this face pointing towards the camera?” or “is this wall perpendicular to that one?” a one-line check.

The angle between two directions

Rearranging gives the angle: θ = acos(a · b ÷ (|a| |b|)). The result is always between 0° and 180°: the dot product does not know which way you turned, only how far. The cross product, in the next lesson, supplies the direction.

WallAngles.cs
using V2 = (double X, double Y); static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y;static double Len(V2 v) => Math.Sqrt(Dot(v, v)); static double AngleDeg(V2 a, V2 b){    double c = Dot(a, b) / (Len(a) * Len(b));    c = Math.Clamp(c, -1, 1);          // rounding can give 1.0000000000000002    return Math.Acos(c) * 180 / Math.PI;} V2 wall = (4, 0);foreach (V2 other in new V2[] { (3, 3), (0, 5), (-2, -2) })    Console.WriteLine($"Dot = {Dot(wall, other)}, angle = {AngleDeg(wall, other):F1} deg");
Output
Dot = 12, angle = 45.0 deg
Dot = 0, angle = 90.0 deg
Dot = -8, angle = 135.0 deg

Projection: how far along, how far off

If u is a unit vector, v · u is the length of v’s “shadow” on u’s line: how far v goes in u’s direction. That is the widget’s green arrow. In BIM terms, with u along a wall, it answers “how far along the wall is this point?”, which is how tools measure a door’s position, a pipe’s station or a dimension along a run.

Use the wall’s perpendicular instead (u turned 90°: (−u.y, u.x)) and the same dot product gives the signed distance off the wall line. Together, the two numbers are the point’s coordinates in the wall’s own system: a first taste of local coordinates.

AlongTheWall.cs
using V2 = (double X, double Y); static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y; V2 a = (1, 1), b = (9, 7);                  // wall location lineV2 p = (6, 6);                              // a column centre V2 ab = (b.X - a.X, b.Y - a.Y);             // (8, 6)double len = Math.Sqrt(Dot(ab, ab));        // 10V2 u = (ab.X / len, ab.Y / len);            // along the wallV2 n = (-u.Y, u.X);                         // across it, to the leftV2 ap = (p.X - a.X, p.Y - a.Y); double along = Dot(ap, u);double across = Dot(ap, n);V2 foot = (a.X + u.X * along, a.Y + u.Y * along); Console.WriteLine($"Along the wall: {along:F2} m of {len} m");Console.WriteLine($"Off the line: {across:F2} m (positive = left side)");Console.WriteLine($"Nearest point on the line: ({foot.X:F2}, {foot.Y:F2})");
Output
Along the wall: 7.00 m of 10 m
Off the line: 1.00 m (positive = left side)
Nearest point on the line: (6.60, 5.20)

If along is below 0 or above the wall’s length, the column lies beyond one end. The Lines and curves module turns this into a full closest-point routine for segments.

Facing: which way does a face point?

Every face has a normal: a unit vector pointing straight out of it. Its dot product with another direction tells you how much the face points that way. With unit vectors, the dot product is cos θ, so it doubles as a “how much” score from −1 to 1. Solar studies, back-face culling in viewers and “which façade does this window belong to?” all use it.

SouthFacing.cs
using V2 = (double X, double Y); static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y; V2 south = (0, -1);var windows = new (string Name, V2 Normal)[]{    ("W1", (0, -1)), ("W2", (0.6, -0.8)), ("W3", (0.8, -0.6)), ("W4", (1, 0)), ("W5", (0, 1))};double limit = Math.Cos(45 * Math.PI / 180);      // within 45 deg of south foreach (var w in windows){    double d = Dot(w.Normal, south);    string verdict = d >= limit ? "faces south" : d > 0 ? "partly south" : "no south sun";    Console.WriteLine($"{w.Name}: dot = {d:F2} -> {verdict}");}
Output
W1: dot = 1.00 -> faces south
W2: dot = 0.80 -> faces south
W3: dot = 0.60 -> partly south
W4: dot = 0.00 -> no south sun
W5: dot = -1.00 -> no south sun
Quick check

a · b is negative. What do you know about a and b?

Quick check

u is a unit vector along a wall from A. For a point P, what does (P − A) · u give?

Practice

Write Relation(a, b) that returns “perpendicular”, “parallel” or “at N deg” for two wall directions, using the dot product of their unit vectors and a tolerance of 1e-9. Test it on (4, 0) & (0, 3), (2, 2) & (−3, −3), (1, 0) & (1, 1) and (3, 4) & (−4, 3).

Show a hint

Normalise both, take the dot product c. |c| near 0 means perpendicular; |c| near 1 means parallel (either way round). Otherwise clamp and use Math.Acos.

Show the solution
Solution.cs
using V2 = (double X, double Y); static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y;static V2 Unit(V2 v) { double l = Math.Sqrt(Dot(v, v)); return (v.X / l, v.Y / l); } static string Relation(V2 a, V2 b){    const double tol = 1e-9;    double c = Dot(Unit(a), Unit(b));    if (Math.Abs(c) < tol) return "perpendicular";    if (Math.Abs(Math.Abs(c) - 1) < tol) return "parallel";    return $"at {Math.Acos(Math.Clamp(c, -1, 1)) * 180 / Math.PI:F1} deg";} Console.WriteLine(Relation((4, 0), (0, 3)));Console.WriteLine(Relation((2, 2), (-3, -3)));Console.WriteLine(Relation((1, 0), (1, 1)));Console.WriteLine(Relation((3, 4), (-4, 3)));
Output
perpendicular
parallel
at 45.0 deg
perpendicular

Remember

  • a · b = a.x·b.x + a.y·b.y + a.z·b.z = |a||b| cos θ: one number, cheap to compute.
  • Its sign says same direction (+), perpendicular (0) or opposite (−).
  • θ = acos(a · b ÷ (|a||b|)); always clamp to [−1, 1] before Acos.
  • With a unit vector u, v · u is v’s projection: how far along u it goes. With the perpendicular, how far off.
  • With unit normals, the dot product scores how much a face points in a direction: compare it with a precomputed cosine.
0 of 44 lessons completed