SitePoint Sponsor 

User Tag List
Results 1 to 11 of 11

Jan 16, 2010, 07:06 #1
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
Adding Distance To GPS Coordinates To Get Bounding Box
I am looking for a method to add distance to a starting GPS coordinate point to create a bounding box (to approximate a circle) which I will then use to find all matches in my MySQL database within that box.
I found this to calculate distances between two GPS coordinates (PHP – Haversine Formula):
http://sgowtham.net/blog/2009/08/04/...scoordinates/
Let's start with these two coordinates (in this format):
Lat = 36.171915
Lon = 115.139974
If I take those two coordinates, I would like to add a distance of 5 miles (or 10 miles or 25 miles or whatever) to them to get north, south, east, and west coordinates 5 miles from the source. I want a point 5 miles due north, a point 5 miles due south, and points 5 miles due east and west.
Then I can take those bounding box coordinates and find anything in my DB within the box.
Does anyone know of any PHP formula or script that can accomplish this with reasonable accuracy?
Any help will be appreciated. I've been searching on this for a couple of hours now.

Jan 16, 2010, 09:19 #2
 Join Date
 Oct 2006
 Location
 France, deep rural.
 Posts
 6,869
 Mentioned
 17 Post(s)
 Tagged
 1 Thread(s)
http://www.sitepoint.com/forums/showthread.php?t=482470
An sql query in which you feed it a lat/lng set a radius and it selects all lat/lngs from a database, is that what you are after?

Jan 16, 2010, 09:55 #3
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
Cups, that is interesting. Thanks for the link. I don't know how accurate that will be.
Even if that worked (I will check it out later) and is accurate, I would still like to be able to know how to do it in PHP script. I would still like to get the coordinates 5 miles out and not just have the DB return matches.
This is the first time I've ever tried to do something like this. Some examples I've seen of calculating the distance between to GPS points don't factor in the curvature of the earth, the distance on the surface. It looked like some of the examples drew a straight line between points going through the earth.
If that SQL query factors in the curvature of the earth, maybe I could deconstruct it and find out how to make it work in PHP.

Jan 18, 2010, 09:20 #4
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
Nobody knows how to do this? Maybe it will be possible to do a little algebra on this MySQL query and get the coordinates.
Code:SELECT * , 6371.04 * ACOS( COS( PI( ) /2  RADIANS( 90  Latitude) ) * COS( PI( ) /2  RADIANS( 90  '$latitude' ) ) * COS( RADIANS( Longitude)  RADIANS( '$longitude' ) ) + SIN( PI( ) /2  RADIANS( 90  Latitude) ) * SIN( PI( ) /2  RADIANS( 90  '$latitude' ) ) ) AS Distance FROM MyLocations WHERE ( 6371.04 * ACOS( COS( PI( ) /2  RADIANS( 90  Latitude) ) * COS( PI( ) /2  RADIANS( 90  '$latitude' ) ) * COS( RADIANS( Longitude)  RADIANS( '$longitude' ) ) + SIN( PI( ) /2  RADIANS( 90  Latitude) ) * SIN( PI( ) /2  RADIANS( 90  '$latitude' ) ) ) <1 ) GROUP BY one_id HAVING dist < '$radius' ORDER BY Distance LIMIT 0 , $numberOfResults

Jan 18, 2010, 10:36 #5
 Join Date
 Jul 2008
 Posts
 5,757
 Mentioned
 0 Post(s)
 Tagged
 0 Thread(s)

Jan 18, 2010, 11:41 #6
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
Thank you, crmalibu. I will test that out.

Jan 18, 2010, 13:22 #7
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
crmalibu,
I tested this:
http://xoxco.com/clickable/phpgetboundingbox
It is not usable. A box consists of 4 points. That script returns 2. And the 2 points it returns are not even on the same line with the original point. If I go a distance out of 1 mile, I would assume that I could draw a straight line between the three pointsthe original and the two new points. But it doesn't.

Jan 18, 2010, 13:51 #8
 Join Date
 Jul 2008
 Posts
 5,757
 Mentioned
 0 Post(s)
 Tagged
 0 Thread(s)
point1 = lat1 lon1
point2 = lat1 lon2
point3 = lat2 lon1
point4 = lat2 lon2

Jan 18, 2010, 14:25 #9
 Join Date
 Oct 2006
 Location
 France, deep rural.
 Posts
 6,869
 Mentioned
 17 Post(s)
 Tagged
 1 Thread(s)
Do you want a bounding box or a radial collection?

Jan 19, 2010, 07:12 #10
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
I am looking for a bounding box (sort of) but not with points in the corners. I want points due north, due south, due east, and due west. When you have points in the corners, your query result will be skewed because of the Pythagorean theorem. If you have a square with a side length of x, the diagonal will be of length x * square root of 2. That (half) will not match the distance I want to go north, south, east and west of the starting point.
I looked at the bearings in the script. They are 0, 90, 180, and 270. Given those bearings, I do not see that this would produce coordinates on the diagonal despite what the author says. The bearings appear to be due north, south, east, and west. I could be wrong.
Since latitude increments from north to south and longitude from east to west, I want points due north and south so I can query everything between the north and south points and do the same with longitude to find matches in my database.
The script linked to by crmalibu is highly accurate for the North coordinate (using the new latitude and the original longitude), but all the other points, especially the south and west, are off. They are short. I'm not looking for points on the diagonal. But if I were, it would not matter because the distances are off.
Here is my entire test script with the unaltered original script followed by an example I tested.
Code:<?php $google_map_url = 'http://maps.google.com/maps?f=q&q={lat},{lon}(Test)&z=15&iwloc=A'; // McKnight & 17th. $lat0 = 45.02091417565888; $lon0 = 93.00496459007263; //Beam & McKnight from http://mapki.com/getLonLat.php //$lat0 = 45.02814095036411; //$lon0 = 93.00500750541687; // Beam & McKnight from script calculation. //$lat0 = 45.028142832457; //$lon0 = 93.004964590073; list($lat1,$lat2,$lon1,$lon2) = getBoundingBox($lat0, $lon0, .5); $url0 = str_replace('{lat}', $lat0, $google_map_url); $url0 = str_replace('{lon}', $lon0, $url0); $url1 = str_replace('{lat}', $lat1, $google_map_url); $url1 = str_replace('{lon}', $lon0, $url1); $url2 = str_replace('{lat}', $lat2, $google_map_url); $url2 = str_replace('{lon}', $lon0, $url2); $url3 = str_replace('{lat}', $lat0, $google_map_url); $url3 = str_replace('{lon}', $lon1, $url3); $url4 = str_replace('{lat}', $lat0, $google_map_url); $url4 = str_replace('{lon}', $lon2, $url4); echo '<a href="' . $url0 . '">url0 Original Coords</a>' . '<br/>'; echo '<a href="' . $url1 . '">url1 New lat1 (South) Original lon</a>' . '<br/>'; echo '<a href="' . $url2 . '">url2 New lat2 (North) Original lon</a>' . '<br/>'; echo '<a href="' . $url3 . '">url3 New lon1 (West) Original lat</a>' . '<br/>'; echo '<a href="' . $url4 . '">url4 New lon2 (East) Original lat</a>' . '<br/>'; // Original script. function getBoundingBox($lat_degrees,$lon_degrees,$distance_in_miles) { $radius = 3963.1; // of earth in miles // bearings $due_north = 0; $due_south = 180; $due_east = 90; $due_west = 270; // convert latitude and longitude into radians $lat_r = deg2rad($lat_degrees); $lon_r = deg2rad($lon_degrees); // find the northmost, southmost, eastmost and westmost corners $distance_in_miles away // original formula from // http://www.movabletype.co.uk/scripts/latlong.html $northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north)); $southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south)); $eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)sin($lat_r)*sin($lat_r)); $westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)sin($lat_r)*sin($lat_r)); $northmost = rad2deg($northmost); $southmost = rad2deg($southmost); $eastmost = rad2deg($eastmost); $westmost = rad2deg($westmost); // sort the lat and long so that we can use them for a between query if ($northmost > $southmost) { $lat1 = $southmost; $lat2 = $northmost; } else { $lat1 = $northmost; $lat2 = $southmost; } if ($eastmost > $westmost) { $lon1 = $westmost; $lon2 = $eastmost; } else { $lon1 = $eastmost; $lon2 = $westmost; } return array($lat1,$lat2,$lon1,$lon2); } ?>
Running the script outputs the following Google Maps links:
Original starting location:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
Point due south using original longitude and lat1 from the script:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
Point due north using original longitude and lat2 from the script:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
Point due west using original latitude and lon1:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
Point due east using original latitude and lon2:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
As I mentioned previously, the distance from our starting point at McKnight & 17th due north to McKnight & Beam is exactly 1/2 mile. The output from the script for the due north point is almost exactly accurate:
http://maps.google.com/maps?f=q&q=45...)&z=15&iwloc=A
Starting at the intersection of McKnight & 17th and going 1/2 mile north, we get a point at the intersection of McKnight & Beam as we should.
As a test, let's move our starting point to Beam and McKnight and look at the south point produced by the PHP script. Starting coordinates are 45.02814095036411, 93.00500750541687.
New original location at Beam & McKnight:
http://maps.google.com/maps?f=q&q=45...9&z=15&iwloc=A
The south point:
http://maps.google.com/maps?f=q&q=45...9&z=15&iwloc=A
We have established the distance from McKnight & 17th north to Beam & McKnight is 1/2 mile (.5). But if you look at the new south point, it is well short of the intersection of McKnight & 17th.
Thus, the script has to be inaccurate.
I have tested this on other distances of 1 mile and 5 miles and have found similar inaccuracies not just with the northsouth points, but with the eastwest points as well.
Even if these points were supposed to be plotted on the diagonal (which I do not want), the northsouth distances would have to be the same. But they are not. I tested those, too.
If anyone has any idea if the original script can be salvaged or if you see any bugs in my code, please let me know.
Or if there are any math and PHP gurus out there that can take the Haversine formula and modify it to return point coordinates instead of a distance, let me know.
I am sure something like this could be beneficial to others. Of course, I did a search here at Sitepoint before I posted this thread. I didn't find any answers and have not found any despite hours of searching on the internet.
Thank you.

Feb 22, 2010, 00:18 #11
 Join Date
 Oct 2005
 Posts
 1,832
 Mentioned
 5 Post(s)
 Tagged
 1 Thread(s)
I got something to work in PHP. You pass the function your starting latitude and longitude in decimal form, the distance you want the new point from your starting point, and the bearing (direction) in degrees and it will return the GPS coordinates of the new point in decimal form. A bearing of 0 is due north, 90 is due east, 180 due south, 270 due west, and anything in between.
$unit can be 'm' for miles or 'km' for kilometers. Just be sure the distance you pass into the function is in the same units.
Code:// Radius of earth. 3959 miles or 6371 kilometers. Must set radius to units you are using, in my case, miles. // Pass in coordinates in Decimal form. Example: 41.5786214 function new_coords($latitude, $longitude, $bearing, $distance, $unit = 'm') { if ($unit == 'm') { $radius = 3959; } elseif ($unit == 'km') { $radius = 6371; } // New latitude in degrees. $new_latitude = rad2deg(asin(sin(deg2rad($latitude)) * cos($distance / $radius) + cos(deg2rad($latitude)) * sin($distance / $radius) * cos(deg2rad($bearing)))); // New longitude in degrees. $new_longitude = rad2deg(deg2rad($longitude) + atan2(sin(deg2rad($bearing)) * sin($distance / $radius) * cos(deg2rad($latitude)), cos($distance / $radius)  sin(deg2rad($latitude)) * sin(deg2rad($new_latitude)))); // Assign new latitude and longitude to an array to be returned to the caller. $coord['latitude'] = $new_latitude; $coord['longitude'] = $new_longitude; return $coord; }
Bookmarks