 Allegro.cc Forums » Programming Questions » Geometry - shortest distance between a point and line

Credits go to Matthew Leverton and SiegeLord for helping out!
 This thread is locked; no one can reply to it.  Geometry - shortest distance between a point and line
Mark Oates
Member #1,146
March 2001 I'm having trouble grasping this simple concept for some reason. Basically I have a point (A) and a line (BC), and I want to find the shortest distance between the two. Knowing that the shortest distance will be a line (AX) that has a slope perpendicular to the slope of BC and goes through A. So the intersection of the two lines is X. For some reason I can't seem to get the math to work out right?! Basically I find the slope-intercept form of both lines and then work the two out to find the x and y coordinates of point X, but this code isn't giving me the correct answers. Here's what I have:

 1 #include "allegro.h" 2 #include 3 4 float d ( float x1, float y1, float x2, float y2) 5 { 6 return sqrt( ((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)) ) ; 7 } 8 9 float shortest_distance(float point_x, float point_y, float line_x1, float line_y1, float line_x2, float line_y2) 10 { 11 // find the slope 12 float slope_of_line = (line_y1 - line_y2) / (line_x1 - line_x2); 13 14 // find the perpendicular slope 15 float perpendicular_slope = (line_x1 - line_x2) / (line_y1 - line_y2) * -1; 16 17 // find the y_intercept of line BC 18 float y_intercept = slope_of_line * line_x2 - line_y2; 19 20 // find the y_intercept of line AX 21 float new_line_y_intercept = perpendicular_slope * -1 * point_x - point_y; 22 23 // get the x_coordinate of point X 24 // equation of BC is y = slope_of_line * x + y_intercept; 25 // equation of AX is y = perpendicular_slope * x + new_line_y_intercept; 26 // perpendicular_slope * x + new_line_y_intercept == slope_of_line * x + y_intercept; 27 // perpendicular_slope * x == slope_of_line * x + y_intercept - new_line_y_intercept; 28 // (perpendicular_slope - slope_of_line) * x == (y_intercept - new_line_y_intercept); 29 float intersect_x = (y_intercept - new_line_y_intercept) / (perpendicular_slope - slope_of_line); 30 31 // get the y_coordinate of point X 32 float intersect_y = slope_of_line * intersect_x + y_intercept; 33 34 // measure the distance between A and X 35 return d(point_x, point_y, intersect_x, intersect_y); 36 } 37 38 39 40 void main() 41 { 42 allegro_init(); 43 44 float point_x = 0; 45 float point_y = -10; 46 float line_x1 = 0; 47 float line_y1 = 0; 48 float line_x2 = 10; 49 float line_y2 = -10; 50 51 float dist = shortest_distance(point_x, point_y, line_x1, line_y1, line_x2, line_y2); 52 dist = d(line_x1, line_y1, line_x2, line_y2); 53 54 allegro_message("%i", (int)dist); 55 } END_OF_MAIN();

What am I doing wrong? SiegeLord Member #7,827 October 2006 Instead of trying to fix your algorithm I shall suggest you a better one. It is faster, and it can handle vertical/horizontal lines(which yours can't as of now).What you do is you find a vector from the first point on the line to the second point. Then you find the absolute value of the cross product between the two vectors(which find the area of the parallelogram formed by the two vectors) and then divide it by the magnitude of the first vector to find the height(which is what you want).Here's the code for that:```int A = x - x1; int B = y - y1; int C = x2 - x1; int D = y2 - y1; int dist = abs(A * D - C * B) / sqrt(C * C + D * D); ``` "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]
 Mark Oates Member #1,146 March 2001 seems to work, but I'm guessing this assumes the line is of infinate length? How should I accomidate for this?
 Matthew Leverton Supreme Loser January 1999 Then it would be the end point.
 Mark Oates Member #1,146 March 2001 Hmm, I still don't understand. How do I know when it's going to be the end point or a point along the line?
SiegeLord
Member #7,827
October 2006 (x1,y1) and (x2,y2) are any two(non-coinciding) on the line. There is no order requirement.

This method does indeed assume an infinite line. It shall return the distance from the line to the point regardless whether the perpendicular projection of it onto the line(point X in your diagram) is actually between the two points.

If you want the distance of a point from a segment(which is what I assume you are referring to) you need a different approach. It is obviously slower.

First you get the above vectors the same way. Then you calculate the dot product between them. You divide that by the length of the line segment to get the length of the projection. Then you divide it again by the same value to get the parameter value of that point. If that point parameter is less than 0, then it is behind the start of the segment, if it is more than 1 then it is in front of the end of the segment. If it is between those two then it is on the segment. You use the parameter to calculate the point(or choose one of the endpoints) and then use the distance formula to find the distance from the two points.

 1 float A = x - x1; 2 float B = y - y1; 3 float C = x2 - x1; 4 float D = y2 - y1; 5 6 float dot = A * C + B * D; 7 float len_sq = C * C + D * D; 8 float param = dot / len_sq; 9 10 float xx,yy; 11 12 if(param < 0) 13 { 14 xx = x1; 15 yy = y1; 16 } 17 else if(param > 1) 18 { 19 xx = x2; 20 yy = y2; 21 } 22 else 23 { 24 xx = x1 + param * C; 25 yy = y1 + param * D; 26 } 27 28 float dist = d(x,y,xx,yy);//your distance function

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

 Mark Oates Member #1,146 March 2001 Thank you SO much! It's working perfectly now.  Fladimir da Gorf Member #1,565 October 2001 SiegeLord, could I by any chance add this function to OpenLayer (Line::GetShortestDistanceTo( const Vec2D &point ))? I think it'd be a nice addition OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 SiegeLord Member #7,827 October 2006 Sure.It should also work for 3D lines/points as well. "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]
 Fladimir da Gorf Member #1,565 October 2001 OK, there it is now, thanks! OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 Go to: Allegro Development Installation, Setup & Configuration Allegro.cc Comments Off-Topic Ordeals The Depot Game Design & Concepts Programming Questions Recent Threads