0

First off, I know that there are answers to questions pertaining this function and i looked through most of them and i could find the answer that I was looking for. What I am trying to do can quite simply be explain in an image:

image diagram of php distance function http://stokemandevelopment.com/pictures/image1.JPG

Now let add some narrative to this image. What I am trying to do is, in MySQL, calculate the distance from the airport to all the airports in my database, and if they fall in between Radius A and Radius B, add them to an array from me to do something with at a later time.

function distance($lat1, $lon1, $lat2, $lon2, $unit) {
  $theta = $lon1 - $lon2;
  $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
  $dist = acos($dist);
  $dist = rad2deg($dist);
  $miles = $dist * 60 * 1.1515;
  $unit = strtoupper($unit);

  if ($unit == "K") {
    return ($miles * 1.609344);
  } else if ($unit == "N") {
     return ($miles * 0.8684);
    } else {
        return $miles;
        }
}

THis is what I currently use to do my caluclations but it is in php, and is extremely slow. I am looking to upgrade the code so that the mysql server does the calculations. I am also trying to do this all in PHP PDO. If anybody can help me, it will be greatly appreciated.

  • Just copy your code in, highlight, and hit the 'code' button - it indents everything four spaces, which is the markdown format for code. – halfer Sep 02 '13 at 18:37
  • possible duplicate of [Get the shortest distance from a point](http://stackoverflow.com/questions/18420419/get-the-shortest-distance-from-a-point) – Micromega Sep 02 '13 at 18:53
  • Did you look at my answer to the question ? I use a quadkey. – Micromega Sep 02 '13 at 23:17
  • Yes, but that is far to complex for what I am trying to do. This is a simple application. All this about complex mathmatics is not necessary. Not to mention it is a little bit above my head and I don't want to using anything that I do not 100% understand myself. I rewrote my code and sped it up considerably. It is not quite what I want, but like I said, it is considerably faster and will serve the purpose of the application for the time being. Thank You to everybody you assisted me with this. – David Stokes Douglas Sep 03 '13 at 01:03

2 Answers2

0

Option 1: Do the calculation on the database by switching to a database that supports GeoIP, or use MySQLs basic GeoIP features.

Option 2: Do the calculation on the database: you're using MySQL, so the following stored procedure should help

CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

If you have an index on latitude and longitude in your database, you can reduce the number of calculations that need to be calculated by working out an initial bounding box in PHP ($minLat, $maxLat, $minLong and $maxLong), and limiting the rows to a subset of your entries based on that (WHERE latitude BETWEEN $minLat AND $maxLat AND longitude BETWEEN $minLong AND $maxLong). Then MySQL only needs to execute the distance calculation for that subset of rows.

If you're simply using the SQL statement provided by skv (or a stored procedure to calculate the distance) then SQL still has to look through every record in your database, and to calculate the distance for every record in your database before it can decide whether to return that row or discard it.

Because the calculation is relatively slow to execute, it would be better if you could reduce the set of rows that need to be calculated, eliminating rows that will clearly fall outside of the required distance, so that we're only executing the expensive calculation for a smaller number of rows.

Considering that what you're doing is basically drawing a circle on a map, centred on your initial point, and with a radius of distance; then the formula simply identifies which rows fall within that circle... but it still has to checking every single row.

Using a bounding box is like drawing a square on the map first with the left, right, top and bottom edges at the appropriate distance from our centre point. Our circle will then be drawn within that box, with the Northmost, Eastmost, Southmost and Westmost points on the circle touching the borders of the box. Some rows will fall outside that box, so SQL doesn't even bother trying to calculate the distance for those rows. It only calculates the distance for those rows that fall within the bounding box to see if they fall within the circle as well.

Within PHP, we can use a very simple calculation that works out the minimum and maximum latitude and longitude based on our distance, then set those values in the WHERE clause of your SQL statement. This is effectively our box, and anything that falls outside of that is automatically discarded without any need to actually calculate its distance.

There's a good explanation of this (with PHP code) on the Movable Type website that should be essential reading for anybody planning to do any GeoPositioning work in PHP.

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Okay, So just to clarify, this will allow me to calculate the distance between points that are WITHIN the minimum and maximum distance that the user provides? – David Stokes Douglas Sep 02 '13 at 23:11
  • You'll have to do a bit of work: use a bounding box based on the outer circle and set that in the WHERE clause of your SQL, calculate the distance for that subset of results in the SQL query select list, then using a HAVING clause that tests that the calculated distance is between the inner circle radius and the outer circle radius – Mark Baker Sep 02 '13 at 23:14
0

You can use a hexagon grid and spiral search around the airport. Here is an example with adjacent tiles: Optimizing search through large list of lat/long coords to find match

Community
  • 1
  • 1
Micromega
  • 12,486
  • 7
  • 35
  • 72