views:

132

answers:

3

I have 2 coordinates. Coordinate 1 is a 'person'. Coordinate 2 is a destination.

How do I move coordinate 1 100 meters closer to coordinate 2?

This would be used in a cron job, so only php and mysql included.

For example:

Person is at: 51.26667, 3.45417

Destination is: 51.575001, 4.83889

How would i calculate the new coordinates for Person to be 100 meters closer?

+5  A: 

Use Haversine to calculate the difference between the two points in metres; then adjust the value of the person coordinates proportionally.

$radius = 6378100; // radius of earth in meters
$latDist = $lat - $lat2;
$lngDist = $lng - $lng2;
$latDistRad = deg2rad($latDist);
$lngDistRad = deg2rad($lngDist);
$sinLatD = sin($latDistRad);
$sinLngD = sin($lngDistRad);
$cosLat1 = cos(deg2rad($lat));
$cosLat2 = cos(deg2rad($lat2));
$a = ($sinLatD/2)*($sinLatD/2) + $cosLat1*$cosLat2*($sinLngD/2)*($sinLngD/2);
if($a<0) $a = -1*$a;
$c = 2*atan2(sqrt($a), sqrt(1-$a));
$distance = $radius*$c;

Feeding your values of:

$lat = 51.26667;        //  Just South of Aardenburg in Belgium
$lng = 3.45417;
$lat2 = 51.575001;      //  To the East of Breda in Holland
$lng2 = 4.83889;

gives a result of 102059.82251083 metres, 102.06 kilometers

The ratio to adjust by is 100 / 102059.82251083 = 0.0009798174985988102859004569070625

$newLat = $lat + (($lat2 - $lat) * $ratio);
$newLng = $lng + (($lng2 - $lng) * $ratio);

Gives a new latitude of 51.266972108109 and longitude of 3.4555267728867

Mark Baker
Following is a good supplement: http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Waleed Al-Balooshi
Interesting, the Haversine. What would you use as R?
Vinko Vrsalovic
i know how to calculate the distance. But don't know how to adjust properly
Topener
Adjust how? For what?
Vinko Vrsalovic
@Vinko Depends how accurate you want the figure. I know it doesn't allow for polar flattening, but the radius figure in my code should be as accurate as most GPS systems
Mark Baker
@Topener Haversine gives you a distance x between the two points. You want to move 100m, so you adjust the lat and long by a ratio of 100/x
Mark Baker
i'm trying to use your function. but i get a rather large number. What would be the output of your function?
Topener
thanks. This really did the trick with your addition
Topener
+4  A: 

If you understand JavaScript, you may want to check out the moveTowards() method in the following Stack Overflow post:

This method returns the destination point when given a start point, an end point, and the distance to travel along that line. You can use point 1 as the starting point, point 2 as the end point, and a distance of 100 meters. It's written in JavaScript, but I'm sure it can be easily ported to PHP or MySQL.

You may also want to check out this other Stack Overflow post which implements a part of the above JavaScript implementation, as a user defined function for SQL Server 2008, called func_MoveTowardsPoint:

The above uses SQL Server 2008's in-built geography data type. However you can easily use two decimal data types for latitude and longitude in place of the single geography data type.

Both the SQL Server and the JavaScript examples were based on implementations from Chris Veness's article Calculate distance, bearing and more between Latitude/Longitude points.

Daniel Vassallo
Interesting postings and links
Mark Baker
+3  A: 

Find the angle theta between the x-axis and the vector from person to destination.

theta = Atan2(dest.y-person.y, dest.x-person.x).

Now use theta and the amount you want to advance the point to calculate the new point.

newPoint.x = advanceDistance * cos(theta) + person.x

newPoint.y = advanceDistance * sin(theta) + person.y

John Wang
The problem with this solution is that it does not consider the earth as a sphere... Degrees of latitude are parallel and are approximately 111km apart, but a degree of longitude is widest at the equator at 111km and gradually converges to zero at the poles.
Daniel Vassallo
Ahh. Didn't read the coordinates are in latitude/longitude.
John Wang
@John: I would still keep the answer here, because it is still relevant (to the title of the question at least)... You may simply want to put a note about this.
Daniel Vassallo