Question

I need to write a reliable method to retrieve the answer to the following scenario...

Given a line segment AB and an arbitrary point C, how would I find the closest point to A on a line parallel to AB that passes through point C? (Reliable mentioned above refers to the algorithms ability to find D while allowing the coordinates for A, B, and C to be completely arbitrary and unpredictable. I've ran in to a quite a few solutions that I was not able to adapt to all possible scenarios, sadly...)

In the case of the data displayed in the picture below, how would I reliably find the x,y coordinates of D?

A = <425, 473>
B = <584, 533>
C = <371, 401>
D = <???, ???>

Knowing that AB and CD are parallel, that obviously means the slopes are the same.

I have tried many different formulas to no avail and have been working on this for weeks now. I'm stumped!

diagram

Was it helpful?

Solution

It's a minimization problem.

In general, the Euclidean distance between two points (A and B) in N dimensional space is given by Dist(A,B) = sqrt((A1-B1)^2 + ... + (AN-BN)^2)

If you need to find the minimum distance between a space curve A(t) (a 1-dimensional object embedded in some N dimensional space) and a point B, then you need to solve this equation:

d Dist(A(t),B) / dt = 0    // (this is straightforward calculus: we're at either a minimum or maximum when the rate of change is 0)

and test that set of roots (t1, t2, etc) against the distance function to find which one yields the smallest value of D.


Now to find the equation for the parallel line passing through C in y=mx+b form:

m = (Ay - By)/(Ax-Bx)
b = Cy - mCx

Let's write this in space-curve form as and plug it into our formula from part 1:

Dist(D(t),A) = sqrt((t-Ax)^2 + (m*t+b-Ay)^2)

taking our derivative:

d Dist(D(t),A)/ dt = d sqrt((t-Ax)^2 + (m*t+b-Ay)^2) / dt 

= (t + (m^2)*t - Ax + m*b - m*Ay)/sqrt(t^2 + (m^2)t^2 - 2*t*Ax + 2*m*t*b - 2*m*t*Ay + (Ax)^2 + (Ay)^2 + b^2 - 2*b*Ay )
= ((1+m^2)*t - Ax + m*b - m*Ay)/sqrt((1+m^2)*(t^2)  + 2*t*(m*b - Ax - m*Ay) + (Ax)^2 + (Ay)^2 + b^2 - 2*b*Ay )

Settings this equal to 0 and solving for t yields: t = (Ax-m*b+m*Ay)/(1+m^2) as the only root (you can check this for yourself by substituting back in and verifying that everything cancels as desired).

Plugging this value of t back in to our space curve yields the following: D=<(Ax-m*b+m*Ay)/(1+m^2),b+m*(Ax-m*b+m*Ay)/(1+m^2)>

You can then plug in your expressions for m and b if you want an explicit solution in terms A,B,C, or if you only want the numerical solution you can just compute it as a three step process:

m = (Ay - By)/(Ax-Bx)
b = Cy - mCx
D=<(Ax-m*b+m*Ay)/(1+m^2),b+m*(Ax-m*b+m*Ay)/(1+m^2)>

This will be valid for all cases with parallel straight lines. One caveat when implementing it as a numerical (rather than analytical) code: if the lines are oriented vertically, calculating m = (Ay-By)/(Ax-Bx) will result in division by 0, which will make your code not work. You can throw in a safety valve as follows:

if( Ax == Bx) {
    D = <Cx,Ay>
} else {
    // normal calculation here
}

For serious numerical work, you probably want to implement that in terms of tolerances rather than a direct comparison due to roundoff errors and all that fun stuff (i.e., abs(Ax-Bx) < epsilon, rather than Ax==Bx)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top