Skip to content

Instantly share code, notes, and snippets.

@zetas
Last active August 29, 2015 14:02
Show Gist options
  • Save zetas/f08f9f89a579c6bcef31 to your computer and use it in GitHub Desktop.
Save zetas/f08f9f89a579c6bcef31 to your computer and use it in GitHub Desktop.
Crazy geospatial radius calculation
<?php
$db = new PDO('mysql:host=localhost;port=3306;dbname=homestead', 'homestead', 'secret');
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
#4980,Long Prairie,MN,verified,45.971955,-94.866789
$lat = 45.971955;
$lon = -94.866789;
$rad = 30; #KM
$R = 6371; // earth's mean radius, km
$maxLat = $lat + rad2deg($rad/$R);
$minLat = $lat - rad2deg($rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $lon + rad2deg($rad/$R/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($rad/$R/cos(deg2rad($lat)));
$sql = "
Select id, name, state, latitude, longitude,
acos(sin(:lat)*sin(radians(latitude)) + cos(:lat)*cos(radians(latitude))*cos(radians(longitude)-:lon)) * :R As D
From (
Select id, name, state, latitude, longitude
From cities
Where latitude Between :minLat And :maxLat
And longitude Between :minLon And :maxLon
) As FirstCut
Where acos(sin(:lat)*sin(radians(latitude)) + cos(:lat)*cos(radians(latitude))*cos(radians(longitude)-:lon)) * :R < :rad
Order by D";
$params = array(
'lat' => deg2rad($lat),
'lon' => deg2rad($lon),
'minLat' => $minLat,
'minLon' => $minLon,
'maxLat' => $maxLat,
'maxLon' => $maxLon,
'rad' => $rad,
'R' => $R,
);
$points = $db->prepare($sql);
$points->execute($params);
foreach ($points as $point) {
echo "$point->id|$point->name|$point->state\n\n";
}
/*
Response with a radius of 30km:
vagrant@homestead:~$ php test.php
4980|Long Prairie|MN
4901|Eagle Bend|MN
5054|Sauk Centre|MN
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment