So lets take the scenario above. We have infinite line black, and point dark blue dot.
How we define an infinite line in vector math is as a point, and a unit vector to define the tangential of that line… the direction. In our image that point will be the red dot.
Now the shortest distance to this line is a straight shot to the line. This will result in a perpendicular line to that infinite line. This is the purple line in the picture.
If using this purple line, you draw a line from the red dot to its meeting point, and a line from the red dot to the blue dot. You get a right triangle (because that purple line is perpendicular).
We can calculate Red → Blue, the hypotenuse. It’s just the point we’re working with subtracted by the red point that defines the infinite line.
We also know the angle between the blue line, and the red line… because the red line and black line are parallel. Lets call that angle theta.
With trig we know that:
blueline = B
redline = R
||B|| = magnitude of B, or length of B
cos(theta) * ||B|| = ||R||
We usually calculate the angle between to vectors as what?
theta = acos((a dot b) / (||a|| * ||b||))
Thing is, we’re going to be cosining, a acos if we do that. And those magnitudes are going to cancel out in that balancing. Leaving that dot product behind.
There’s a reason for this. Dot product does what we call “projects” one vector onto another.
If we project a vector onto a unit vector, it’ll tell us how long in the dimension of that vector to go (this works because a unit vectors magnitude is 1, which is the identity value in that equation above… it effectively cancels it out). Our black line is defined as a point with a unit vector!
SO… if we dot product the blue line onto the vector in the direction of the black line. We’ll get the length of… red. And we already know the direction of red.
So, lets assume our R is black line in this, a unit vector, and lets call that R’. If we replace accordingly where a = R’ and b = B we get. But in our case R’ is a unit vector for calculating the angle, because we’re using the black line for that. SO, ||R’|| = 1.
acos((R’ dot B) / (1 * ||B||))
insert into our previous equation:
cos(acos((R’ dot B) / (1 * ||B||))) * ||B|| = ||R||
reduce:
||B|| * (R’ dot B) / ||B|| = ||R||
R’ dot B = ||R||
So if we take the dot product of the direction of blackline and the blueline, we get the length redline aught to be. And if we just multiply that by the direction of red/black line, add that to the start point, we get the end point.
//linePnt - point the line passes through
//lineDir - unit vector in direction of line, either direction works
//pnt - the point to find nearest on line for
public static Vector3 NearestPointOnLine(Vector3 linePnt, Vector3 lineDir, Vector3 pnt)
{
lineDir.Normalize();//this needs to be a unit vector
var v = pnt - linePnt;
var d = Vector3.Dot(v, lineDir);
return linePnt + lineDir * d;
}
Replace this with Vector2 if you wanted to do it in 2d. The operations are identical.
This technically even works in 4 dimensions… though the concept of a straight line in 4 dimensions gets really weird.