Reputation: 81
I have a database of airports with Latitude and Longitude for each point. I want to run a PHP script to find all airports that are nearby a given airport, with their distance and relative direction.
I.e. for Airport KLDJ (40-37-02.810N 074-14-40.539W)
Airport Nearby
KJFK - John F Kennedy Airport (21.2 nm NE) (40-38-23.104N 073-46-44.132W)
I have used code from http://www.movable-type.co.uk/scripts/latlong.html to find distance, and tried to use it to find bearing, which might not be right.
//BEARING RHUMB LINE
$phi = log(tan($lat2/2+pi/4)/tan($lat1/2+pi/4));
$distance['bearing'] = (rad2deg(atan2($theta, $phi)) +180) % 360;
I basically want to run all points through this script and find the distance, which I have already, but then the direction. (i.e. N, S, W, E, NW, SW, NE, SE)
Upvotes: 2
Views: 5494
Reputation: 23749
Looking at another page from the same website:
$lat = 0; // latitude of centre of bounding circle in degrees
$lon = 0; // longitude of centre of bounding circle in degrees
$rad = 0; // radius of bounding circle in chosen units
// Choose your unit of measure...
$r = 6371; // earth's radius in km
$r = 3959; // earth's radius in miles
// or
$r = 3440; // earth's radius in nautical miles
// convert point of origin to radians
$lat = deg2rad($lat);
$lon = deg2rad($lon);
// first-cut bounding box (in radians)
$maxLat = $lat + $rad / $r;
$minLat = $lat - $rad / $r;
// compensate for longitude getting smaller with increasing latitude
$maxLon = ( $lon + $rad / $r ) / cos( $lat );
$minLon = ( $lon - $rad / $r ) / cos( $lat );
combined with the query:
$query = 'SELECT
id
, lat
, lon
, ACOS(SIN('.$lat.') * SIN(RADIANS(lat)) + COS('.$lat.') * COS(RADIANS(lat)) * COS(RADIANS(lon) - '. $lon.')) * '.$r.' AS distance
FROM (
SELECT
id
, lat
, lon
FROM MyTable
WHERE
RADIANS(lat) > $minLat AND RADIANS(lat) < '.$maxLat.'
AND
RADIANS(lon) > $minLon AND RADIANS(lon) < '.$maxLon.'
) AS FirstCut
WHERE ACOS(SIN('.$lat.') * SIN(RADIANS(lat)) + COS('.$lat.') * COS(RADIANS(lat)) * COS(RADIANS(lon) - '. $lon.')) * '.$r.' < '.$rad;
Selects you a list of locations (and their distance from the origin of your circle) within the bounding circle you specified.
The only thing left to do is calculate a bearing for the locations returned. Which can be done with your rhumb line formula.
The above assumes you have your database filled with coordinates in degrees.
If you had you locations stored as geometry objects, you could use MySQL's inbuilt spatial functions. Although I'm quite sure MySQL does only include bounding rectangles.
Upvotes: 1
Reputation: 105868
Heavily borrowing from the techniques here and using data from here, I put together this example
<?php
$chicago = array(
'lat' => 41.9
, 'lng' => 87.65
);
$dallas = array(
'lat' => 32.73
, 'lng' => 96.97
);
$ftworth = array(
'lat' => 32.82
, 'lng' => 97.35
);
$bearing = getBearingBetweenPoints( $dallas, $chicago );
echo "Bearing: $bearing°<br>";
echo "Direction: " . getCompassDirection( $bearing );
function getBearingBetweenPoints( $point1, $point2 )
{
return getRhumbLineBearing( $point1['lat'], $point2['lng'], $point2['lat'], $point1['lng'] );
}
function getRhumbLineBearing($lat1, $lon1, $lat2, $lon2) {
//difference in longitudinal coordinates
$dLon = deg2rad($lon2) - deg2rad($lon1);
//difference in the phi of latitudinal coordinates
$dPhi = log(tan(deg2rad($lat2) / 2 + pi() / 4) / tan(deg2rad($lat1) / 2 + pi() / 4));
//we need to recalculate $dLon if it is greater than pi
if(abs($dLon) > pi()) {
if($dLon > 0) {
$dLon = (2 * pi() - $dLon) * -1;
}
else {
$dLon = 2 * pi() + $dLon;
}
}
//return the angle, normalized
return (rad2deg(atan2($dLon, $dPhi)) + 360) % 360;
}
function getCompassDirection( $bearing )
{
static $cardinals = array( 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N' );
return $cardinals[round( $bearing / 45 )];
}
Upvotes: 7
Reputation: 3321
You can check, if the latitude of position B is larger or smaller than the latitude of position A to determine if it's in the east or in the west. Same thing with the longitude for north and south. Finally you need a threshold, to detect, in which case the drift is large enough to switch to an intermediate direction.
Upvotes: 1