Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

Please refer to the example and corresponding image.

I would like to achieve the following: provide two locations (lat/lng), which are shown below as A and B. From this, a virtual line would be drawn and then the distance between this line and C would be calculated (in any measurement).

drawing

I have achieved this currently in Google Maps API v3 but would want to also be able to perform this behind the scenes in my language of choice. Any tips/ideas would be greatly appreciated!

share|improve this question
    
Is AB a Great Circle line? –  Kirk Kuykendall Jun 23 '11 at 16:05
    
@Kirk, No, AB is just a straight line –  Prisoner Jun 23 '11 at 16:14
    
@Michael, thats an interesting point. I will have to have a look into it! –  Prisoner Jun 23 '11 at 16:15
    
@Prisoner @Kirk Literally, a "straight line" will pass beneath the earth's surface. In general, its radial projection back onto the surface will indeed be a segment of a great circle (using a spherical earth model). –  whuber Jun 23 '11 at 16:26
1  
@Prisoner That is an extremely useful extra piece of information! Yes, you are correct. You still have to compensate for the fact that using (lat,lon) differentially distorts east-west distances compared to north-south. As @Jose advises, project the coordinates. This can be as simple as pre-multiplying the longitudes by the cosine of the average latitude and then pretending you're on a Euclidean plane. –  whuber Jun 23 '11 at 16:32
show 3 more comments

3 Answers 3

up vote 4 down vote accepted
def get_perp( X1, Y1, X2, Y2, X3, Y3):
"""************************************************************************************************ 
Purpose - X1,Y1,X2,Y2 = Two points representing the ends of the line segment
          X3,Y3 = The offset point 
'Returns - X4,Y4 = Returns the Point on the line perpendicular to the offset or None if no such
                    point exists
'************************************************************************************************ """
XX = X2 - X1 
YY = Y2 - Y1 
ShortestLength = ((XX * (X3 - X1)) + (YY * (Y3 - Y1))) / ((XX * XX) + (YY * YY)) 
X4 = X1 + XX * ShortestLength 
Y4 = Y1 + YY * ShortestLength
if X4 < X2 and X4 > X1 and Y4 < Y2 and Y4 > Y1:
    return X4,Y4
return None

The shortest length is the distance you require, unless I am mistaken?

share|improve this answer
    
Yes, I am looking for the shortest distance from C to the line segment. Is this what this math computes? –  Prisoner Jun 24 '11 at 9:30
    
this gives you the point on the line and the shortest distance. –  Hairy Jun 24 '11 at 9:35
1  
@Hairy, One last thing, how would I go about modifying this to go to the nearest point (not just line) so if I had put it past the point of joing a line, how could I get it to check the distance to the point? –  Prisoner Jun 24 '11 at 14:47
1  
@Hairy Good start, but it seems that too often this code returns None when a legitimate solution exists. The problem is that the last conditional assumes X1 < X2 and Y1 < Y2, which cannot always be assured. A better test of betweenness is needed. –  whuber Jun 26 '11 at 18:11
1  
@Hairy It sounds like this exchange between you and @prisoner has been productive. I would like to emphasize that I have had nothing to do with (or even any control over) any changes in voting or points that may have occurred and that my comment was intended only to help you improve your reply. –  whuber Jun 27 '11 at 13:18
show 15 more comments

Maybe I'm making it too complicated, but what you want is the distance from a point to a line. That is the distance from a point along AB that links AB with C with a line orthogonal to AB. This vector perpendicular to AB is given by

v=[x2-x1, -(y2-y1)] # Point A is [x1,y1] Point B is [x2,y2]

(I have used the square brackets to define a vector, or a two-element array). The distance between C [xp, yp] and point A is

u=[x1-xp, y1-xp]

The distance between the line and C is just the projection of u on to v. If we assume mod(v) = 1 (just normalise it), then

distance = u*v = abs( (x2-x1)*(y1-yp) - (x1-xp)*(y2-y1) )

The only complication is that you probably want to make sure your coordinates are not WGS84 lat/log pairs, but projected (or use geodetic coordinates). You can use OGR or Proj4 for this.

share|improve this answer
3  
+several million pseudo-points for not using trigonometric functions, by the way. All too many people pull out ArcTan when they should be looking at this: en.wikipedia.org/wiki/Dot_product –  Herb Jun 23 '11 at 16:11
    
@Jose, thanks for the reply! I'm using the lat/long from google maps API. The maths part is quite new to me so I'll give it a go and see what I can come up with. Any tips with the maths? E.g. [x2-x1, -(y2-y1)], what does that translate to? –  Prisoner Jun 23 '11 at 16:21
    
I have added a short edit for this. Basically, it's an array notation, but if you store your coordinates in variables x1, x2, y1, y2 and xp, yp, you only need to write the right hand side of the last equation I've provided. This is pretty much valid C, Java, JS, Python etc code :) –  Jose Jun 23 '11 at 16:26
1  
@Jose You are computing the distance from C to the line AB. Based on the figure, I believe the OP wants the distance from C to the line segment AB. This requires extra work to check whether the projection of C onto line AB lies between A and B or not. In the latter case, use the shorter of the two lengths CA and CB. –  whuber Jun 23 '11 at 16:29
1  
@Prisoner The main difference is that a line extends forever (it is only defined by a direction vector and a point, or by two points), whereas a segment between A and B is the bit of the the infinite line that goes between A and B (it has a finite length) –  Jose Jun 23 '11 at 17:25
show 3 more comments

Being a bit averse to all this math as well, I would come at it from a different angle. I would make it an 'actual' line, rather than a virtual line, and then use existing tools.

If A and B share an attribute, you could connect them by drawing a line (Kosmo GIS has a tool that will create lines from points, and I believe there is also a QGIS plugin for this). Once you have the lines, a 'near' function on the 'C' point layer will give you the distance to the line. Let the software handle the math for you!

share|improve this answer
    
Thanks for the comment but Hairy came up trumps on this one! –  Prisoner Jun 24 '11 at 12:01
1  
(+1) You make an excellent point. Computational geometry algorithms are notoriously tricky to get completely right in practice (as we can see from all the code offered so far, which is helpful and illustrative but doesn't yet fully work). Using a high-level GIS procedure often is a good way to assure you are getting the answer you expect and that it's right (provided you trust your GIS ;-). –  whuber Jun 27 '11 at 13:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.