-
Notifications
You must be signed in to change notification settings - Fork 14
/
GreatCircle.php
64 lines (56 loc) · 2.67 KB
/
GreatCircle.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
Class GreatCircle {
const M = 6371009;
const KM = 6371.009;
const MI = 3958.761;
const NM = 3440.070;
const YD = 6967420;
const FT = 20902260;
private function validateRadius($unit) {
if ( defined('self::'.$unit) ) { return constant('self::'.$unit); }
else if ( is_numeric($unit) ) { return $unit; }
else { throw new Exception('Invalid unit or radius: '.$unit); }
}
// Takes two sets of geographic coordinates in decimal degrees and produces distance along the great circle line.
// Optionally takes a fifth argument with one of the predefined units of measurements, or planet radius in custom units.
public static function distance($lat1, $lon1, $lat2, $lon2, $unit = KM) {
$r = self::validateRadius($unit);
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat2 = deg2rad($lat2);
$lon2 = deg2rad($lon2);
$lonDelta = $lon2 - $lon1;
$a = pow(cos($lat2) * sin($lonDelta) , 2) + pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($lonDelta) , 2);
$b = sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) * cos($lonDelta);
$angle = atan2(sqrt($a) , $b);
return $angle * $r;
}
// Takes two sets of geographic coordinates in decimal degrees and produces bearing (azimuth) from the first set of coordinates to the second set.
public static function bearing($lat1, $lon1, $lat2, $lon2) {
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat2 = deg2rad($lat2);
$lon2 = deg2rad($lon2);
$lonDelta = $lon2 - $lon1;
$y = sin($lonDelta) * cos($lat2);
$x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($lonDelta);
$brng = atan2($y, $x);
$brng = $brng * (180 / pi());
if ( $brng < 0 ) { $brng += 360; }
return $brng;
}
// Takes one set of geographic coordinates in decimal degrees, azimuth and distance to produce a new set of coordinates, specified distance and bearing away from original.
// Optionally takes a fifth argument with one of the predefined units of measurements or planet radius in custom units.
public static function destination($lat1, $lon1, $brng, $dt, $unit = KM) {
$r = self::validateRadius($unit);
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat3 = asin(sin($lat1) * cos($dt / $r) + cos($lat1) * sin($dt / $r) * cos(deg2rad($brng)));
$lon3 = $lon1 + atan2(sin(deg2rad($brng)) * sin($dt / $r) * cos($lat1) , cos($dt / $r) - sin($lat1) * sin($lat3));
return array(
"LAT" => rad2deg($lat3) ,
"LON" => rad2deg($lon3)
);
}
}
?>