Lines, rays and segments in parametric form
One formula, P(t) = A + t·d, describes a line, a ray and a segment: only the allowed range of t changes. Learn to read t, to walk along a wall by distance, and why BIM tools never use y = mx + c.
One formula, three shapes
| Shape | Allowed t | In a BIM model |
|---|---|---|
Line class with Line.CreateBound(p1, p2) and Line.CreateUnbound(origin, direction), and a Curve.IsBound property. A bound line is a segment and an unbound one is infinite: the same formula with a different range of t.
Two choices of direction
| Direction d | t means | B is at | Use it when you think in |
|---|---|---|---|
V2 struct, the 2D cousin of the Vec3 from the last module. It is repeated at the bottom of each sample, so every sample runs on its own.
var a = new V2(2, 1);var b = new V2(10, 7);V2 d = b - a; // (8, 6): a 10 m wall foreach (double t in new[] { 0, 0.25, 0.5, 1, 1.5 }) Console.WriteLine($"t = {t,-4} P = {a + d * t}"); V2 u = d * (1 / d.Length); // unit direction (0.8, 0.6)Console.WriteLine($"1.2 m along: {a + u * 1.2}");Console.WriteLine($"3 m along: {a + u * 3}"); 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 static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y; public static double Cross(V2 a, V2 b) => a.X * b.Y - a.Y * b.X; public double Length => Math.Sqrt(X * X + Y * Y); public override string ToString() => $"({X:0.###}, {Y:0.###})";}t = 0 P = (2, 1) t = 0.25 P = (4, 2.5) t = 0.5 P = (6, 4) t = 1 P = (10, 7) t = 1.5 P = (14, 10) 1.2 m along: (2.96, 1.72) 3 m along: (4.4, 2.8)
Finding t for a point
var a = new V2(2, 1);var b = new V2(10, 7);V2 d = b - a; foreach (var q in new V2[] { new(6, 4), new(14, 10), new(-2, -2) }){ double t = V2.Dot(q - a, d) / V2.Dot(d, d); string where = t < 0 ? "behind A" : t > 1 ? "past B" : "on the wall"; Console.WriteLine($"{q}: t = {t}, {where}");} 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 static double Dot(V2 a, V2 b) => a.X * b.X + a.Y * b.Y; public static double Cross(V2 a, V2 b) => a.X * b.Y - a.Y * b.X; public double Length => Math.Sqrt(X * X + Y * Y); public override string ToString() => $"({X:0.###}, {Y:0.###})";}(6, 4): t = 0.5, on the wall (14, 10): t = 1.5, past B (-2, -2): t = -0.5, behind A
Lines in 3D: nothing changes
var start = new V3(0, 0, 3.0); // invert level at the manholevar end = new V3(20, 0, 2.5); // 0.5 m lower, 20 m away: a 1:40 fallV3 d = end - start; for (double x = 0; x <= 20; x += 5){ V3 p = start + d * (x / d.X); // t from the horizontal distance Console.WriteLine($"Station {x,2} m: invert {p.Z:F3} m");} readonly record struct V3(double X, double Y, double Z){ public static V3 operator +(V3 a, V3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); public static V3 operator -(V3 a, V3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); public static V3 operator *(V3 v, double k) => new(v.X * k, v.Y * k, v.Z * k); public static double Dot(V3 a, V3 b) => a.X * b.X + a.Y * b.Y + a.Z * b.Z; public double Length => Math.Sqrt(Dot(this, this)); public override string ToString() => $"({X:0.###}, {Y:0.###}, {Z:0.###})";}Station 0 m: invert 3.000 m Station 5 m: invert 2.875 m Station 10 m: invert 2.750 m Station 15 m: invert 2.625 m Station 20 m: invert 2.500 m
PointAt(a, b, s) that returns the point s metres along the beam, measured along its own length. Print the beam’s length and a bolt position every 2.5 m from one end to the other.
Show a hint
Show the solution
var a = new V3(1, 2, 3);var b = new V3(9, 2, 9);double length = (b - a).Length;Console.WriteLine($"Length: {length} m"); for (double s = 0; s <= length + 1e-9; s += 2.5) Console.WriteLine($"{s,4} m: {PointAt(a, b, s)}"); static V3 PointAt(V3 a, V3 b, double s){ V3 d = b - a; return a + d * (s / d.Length); // unit direction times distance} readonly record struct V3(double X, double Y, double Z){ public static V3 operator +(V3 a, V3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); public static V3 operator -(V3 a, V3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); public static V3 operator *(V3 v, double k) => new(v.X * k, v.Y * k, v.Z * k); public static double Dot(V3 a, V3 b) => a.X * b.X + a.Y * b.Y + a.Z * b.Z; public double Length => Math.Sqrt(Dot(this, this)); public override string ToString() => $"({X:0.###}, {Y:0.###}, {Z:0.###})";}Length: 10 m 0 m: (1, 2, 3) 2.5 m: (3, 2, 4.5) 5 m: (5, 2, 6) 7.5 m: (7, 2, 7.5) 10 m: (9, 2, 9)
Remember
A line in parametric form is P(t) = A + t·d: a start point plus a multiple of a direction. Line, ray and segment are the same formula; t is unrestricted, t ≥ 0, or 0 ≤ t ≤ 1. With d = B − A, t is a fraction of the way; with a unit d, t is a distance in model units. Find the t of a point with a projection: t = (Q − A)·d ÷ (d·d). It works unchanged in 3D, and it handles vertical lines that y = mx + c cannot.