PHP MySql and geolocation

拟墨画扇 提交于 2019-11-27 19:11:35

Calculating the distance using that function there is pretty computationally expensive, because it involves a whole bunch of transcendental functions. This is going to be problematic when you have a large number of rows to filter on.

Here's an alternative, an approximation that's way less computationally expensive:

Approximate distance in miles:

sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 53.0 * (lon2 - lon1) 

You can improve the accuracy of this approximate distance calculation by adding the cosine math function:

Improved approximate distance in miles:

sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 

Source: http://www.meridianworlddata.com/Distance-Calculation.asp


I ran a bunch of tests with randomly generated datasets.

  • The difference in accuracy for the 3 algorithms is minimal, especially at short distances
  • The slowest algorithm is, of course, the one with the trig functions (the one on your question). It is 4x slower than the other two.

Definitely not worth it. Just go with an approximation.
Code is here: http://pastebin.org/424186


To use this on MySQL, create a stored procedure that takes coordinate arguments and returns the distance, then you can do something like:

SELECT columns 
  FROM table 
 WHERE DISTANCE(col_x, col_y, target_x, target_y) < 25

You may want to take a look at this solution - a somewhat brilliat workaround.

You can do it easily in two steps:

  • Find all locations within 25 miles in each direction of the point. This will look like: WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2

  • Then loop through each result and check to see if it really is within 25 miles using your code. (i.e., Filter out those locations that are in the corners of the square.)

For the first part, here's some code I have laying around (don't remember the source):

$lat_range = $radius / ((6076 / 5280) * 60);
$lng_range = $radius / (((cos(($city['lat'] * 3.141592653589 / 180)) * 6076) / 5280) * 60);

Basically just use ($lat - $lat_range, $lat + $lat_range) and ($lng - $lng_range, $lng + $lng_range) Radius is in miles.

Obviously you can clean up the math a bit.

Edit: I forgot to mention that you would need to tweak it a bit if you need to support locations near the equator, international date line, etc. Obviously for North America, it would be fine as-is.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!