3D Nearest Point on a 3d line to a point (Get the point?)

RujiK

Member
It's me, the 100% 3D Math genius who needs some help.

I have a point (xx,yy,zz) and an infinite vector/3d line defined by two points (x0,y0,z0) and (x1,y1,z1). How do I find the NEAREST POINT ON THE LINE to my other point?

THAT'S IT! But here is some fluff to show you that I did try wicked hard:


FLUFF: (Feel free to ignore the rest if you are 3d smart)

Currently, I can find the DISTANCE between the line and the point, but I need the position and I'm not sure if the distance actually helps.

GML:
    //Find distance from point to vector. THIS WORKS!
    V1 = [x0,y0,z0]; //start of vector
    V2 = [x1,y1,z1]; //end of vector
    point = [xx,yy,zz];
    _diff[0] = V1[0] - point[0];
    _diff[1] = V1[1] - point[1];
    _diff[2] = V1[2] - point[2];

    _sum[0] =  (_diff[1]*V2[2] - _diff[2]*V2[1]);
    _sum[1] = -(_diff[0]*V2[2] - _diff[2]*V2[0]);
    _sum[2] =  (_diff[0]*V2[1] - _diff[1]*V2[0]);
        
    _distance = (sqrt(_sum[0]*_sum[0] + _sum[1]*_sum[1] + _sum[2]*_sum[2]) /
                 sqrt(V2[0] * V2[0] + V2[1] * V2[1] + V2[2] * V2[2] ));
I also have this kind of working code that finds the closest point on the line, but it seems to have some mistakes as sometimes it gives weird answers.
GML:
//Find nearest point on line to other point. Kind of works?
P1 = [xx,yy,zz];
V1 = [x0,y0,z0]; //start of vector
V2 = [x1,y1,z1]; //end of vector

var u = ((P1[0] - V1[0]) * (V2[0] - V1[0])) 
      + ((P1[1] - V1[1]) * (V2[1] - V1[1])) 
      + ((P1[2] - V1[2]) * (V2[2] - V1[2]));
      
var dist = point_distance_3d(x0,y0,z0,x1,y1,z1);
u = u/(dist*dist)

closest_point[0] = V1[0] + u * (V2[0] - V1[0]);
closest_point[1] = V1[1] + u * (V2[1] - V1[1]);
closest_point[2] = V1[2] + u * (V2[2] - V1[2]);

I've also found several code non-GML explanations of how to do this, but they are all with vector libraries and I have no idea what they are doing under the hood. Here are two examples I found but can't interpret:

Code:
public Vector2 FindNearestPointOnLine(Vector2 origin, Vector2 direction, Vector2 point)
{
    direction.Normalize();
    Vector2 lhs = point - origin;

    float dotP = Vector2.Dot(lhs, direction);
    return origin + direction * dotP;
}
Code:
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;
Links for above code:
https://stackoverflow.com/questions/9368436/3d-perpendicular-point-on-line-from-3d-point
https://stackoverflow.com/questions/51905268/how-to-find-closest-point-on-linepublic static Vector3

I would appreciate any help. I've been coming back to this for over a week now. (Generous upvotes if that is any incentive) Thanks!
 

FrostyCat

Member
The main driver of this is the vector dot product, which is a measure of how much a vector points in the same direction as another vector. An immediate application of this is the vector projection (the shadow of a vector when mapped flat onto another), and the formulas you observed are basically the ray's starting point plus the projection.

An equivalent in GML is this:
GML:
///@func nearestPointOnLine(ox, oy, oz, rx, ry, rz, px, py, pz)
var ox = argument0,
    oy = argument1,
    oz = argument2,
    rx = argument3,
    ry = argument4,
    rz = argument5,
    px = argument6,
    py = argument7,
    pz = argument8;

// Normalize the ray vector
var rMag = point_distance_3d(0, 0, 0, rx, ry, rz);
rx /= rMag;
ry /= rMag;
rz /= rMag;

// Calculate the pointing vector (origin to point)
var opx = px-ox,
    opy = py-oy,
    opz = pz-oz;

// Dot product
var dp = dot_product_3d(rx, ry, rz, opx, opy, opz);

// Result: o+(r'.(p-o))r'
return [ox+dp*rx, oy+dp*ry, oz+dp*rz];
Edit (2020-04-08): Made a mistake in the formula before, now fixed.

Please, don't touch 3D without the basics of vector geometry and linear algebra. Learn what vector addition/subtraction, scalar-vector multiplication, dot product, cross product, matrix multiplication, and homogeneous coordinates are. If you aren't speaking the lingo, you're wasting everyone's time.
 
Last edited:

NightFrost

Member
A little off topic, and I don't know what your level of familiarity with the subject is, but in regards to linear algebra, this video series I've been watching seems a very good introduction to it.
 
Top