Miss-using Vector Projection

Hey, I’m having a complete brain freeze moment here and my frustration has finally outweighed my embarrassment to the point I’m reaching out for help.

I have three objects in space (A, B and C).
I want to find the closest point to C on the line between A and B. (Represented by D)

So I tried first finding the Vector of the line AB by subtraction, but that line of course passes through 0,0.
Meaning if I try to project from C to AB it won’t take into account the offset from 0,0 of the real AB. (The projection I wanted is in blue, the projection result is in red).

But I think I’m going about this entirely wrong because even if I got Vector.Project() to work in this way I would have to solve the issues with cases like J where a projection would give me a result outside of AB’s range.
Granted that wouldn’t be a hard fix but I feel like there’s a more elegant solution to this problem I’m not familiar with.

So my question becomes how should I be going about this?
I feel like I’ve wasted most my morning overthinking what should have been a very simple problem.

Get vector’s AB and AC.

Normalize vector |AB|.

Dot Product AC onto |AB| getting the projection of AC on |AB|.

Multiply that scalar projection by |AB| and add that vector to A.

That should give you D.

Vector3 ab = B - A;
Vector3 ac = C - A;
ab = ab.normalized;

float proj = Vector3.Dot(ac, ab);
Vector3 D = A + ab * proj;

Well if it falls out of the range the projection (the dot product) would be negative or larger than the distance AB. In that case, the nearest point is the end point. If negative it’s A, if larger than len(AB) than it’s B.

Though technically the values you got are the ‘nearest’ points in the first place (J that is). This is just adding on the constraint that those points exist with in the segment AB.

Vector3 D;
if(proj < 0f)
    D = A;
else if(proj > (B - A).magnitude)
    D = B;
else
    D = A + ab * proj;
1 Like

Interestingly enough, someone just liked another post of mine that deals with this same exact thing:

In it I have a much more stream-lined implementation of the code I covered:

public static Vector3 NearestPointOnFiniteLine(Vector3 start, Vector3 end, Vector3 pnt)
{
    var line = (end - start);
    var len = line.magnitude;
    line.Normalize();
   
    var v = pnt - start;
    var d = Vector3.Dot(v, line);
    d = Mathf.Clamp(d, 0f, len);
    return start + line * d;
}
1 Like

That was me! Because your post - which I stumbled upon via googling - was exceptionally useful in my quest to get my collision detection code working properly. So now I just want to say thanks!

1 Like

You bloody beauty!
Looks like I need to pick up a book on linear algebra, I wasn’t familiar with that solution at all.
Thanks a million.