I'm trying to implement the calculation of the distance from a point to a line in a 3d space in C . For the line I'm given the direction of the line and a point on the line, as well as the point I'm calculating the distance from. How would I go about doing this?
I've never done this before when given the direction of the line and a point, I've only done it when given the start and end points of line, so I'm a bit stuck, and I'm not really sure what to search and can't find much info of what to do when only given the direction.
Any help would be appreciated. Thanks.
CodePudding user response:
See the algorithm in XMVector3LinePointDistance
library function in Windows SDK. The source code is on github. Because your line is specified as a point and direction vector, just delete the line of code which computes LineVector
variable.
Here’s a slow stand-alone version of that algorithm.
// 3D vector
struct float3
{
float x, y, z;
float3 operator-( float3 v ) const
{
return float3{ x - v.x, y - v.y, z - v.z };
}
void operator -=( float3 v )
{
x -= v.x; y -= v.y; z -= v.z;
}
float3 operator*( float s ) const
{
return float3{ x * s, y * s, z * s };
}
};
// Dot product of 3D vectors
float dot( float3 a, float3 b )
{
return a.x * b.x a.y * b.y a.z * b.z;
}
// Length of a 3D vector
float length( float3 v )
{
return std::sqrt( dot( v, v ) );
}
// Distance between line and point in 3D
float distanceToLine( float3 line0, float3 lineDir, float3 point )
{
// Translate point making it relative to the start of the line
point -= line0;
// Coefficient to get closest point on the line,
// equal to length(point) * cos(angle) / length(lineDir)
float pl = dot( lineDir, point ) / dot( lineDir, lineDir );
// Position of the closest point on the line
float3 closest = lineDir * pl;
// Compute distance between two points
return length( point - closest );
}
The above code does the math in FP32 precision, it’s a direct port from that DirectXMath library. If you want better FP64 precision for your use case, replace float
with double
everywhere.
CodePudding user response:
Assuming you have a location vector b
(base of the line), the direction vector d
and finally your point p
as location vector then you can calculate a vector round trip such that
b k*d c - p = o
with c
= 'connection' vector between line and point, o
= origin vector with all coordinates 0 and k
a yet unkown number. However d and c should be orthogonal to minimise, thus their cross product needs to get 0. With these conditions you get an equation system you then can solve, and the length of c then is equal to the distance between line and point:
bx k * dx cx - px = 0
by k * dy cy - py = 0
bz k * dz cz - pz = 0
dx*cx dy*cy dz*cz = 0
For equations for four unkown variables (k
, cx
, cy
, cz
) and all others (b*
, d*
, p*
) already given. Changing the representation a bit you get:
cx dx * k bx-px = 0
cy dy * k by-py = 0
cz dz * k bz-pz = 0
dx * cx dy * cy dz * cz = 0
showing how you can easily eliminate the c*
from last line by subtracting appropriate multiples of the first three lines to, which will give you result for k. This one you you then can apply in the other equations – and you are done with the calculation of c
(see Gaussian elimination). Then all you yet need to calculate is the length of c
as sqrt(cx*cx cy*cy cz*cz)
.
If you go a step further you can deduce a closed formula for k
from:
- dx*dx*k - dx(bx-px) - dy*dy*k - dy*(by-py) - dz*dz*k - dz*(bz-pz) = 0
<=> (dx*dx dy*dy dz*dz) * k = dx*(px-bx) dy*(py-by) dz(pz-bz)
<=> k = (dx*(px-bx) dy*(py-by) dz(pz-bz)) / (dx*dx dy*dy dz*dz)
Note: It's the cross product of p-b
and d
divided by the length of d
.