Completed
Push — master ( 9405e1...3c4dfe )
by Marcus
02:01
created

BearingSpherical::calculateBearing()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
rs 9.4285
cc 2
eloc 11
nc 2
nop 2
1
<?php
2
/**
3
 * Calculation of bearing between two points using a
4
 * simple spherical model of the earth.
5
 *
6
 * @author   Marcus Jaschen <[email protected]>
7
 * @license  https://opensource.org/licenses/GPL-3.0 GPL
8
 * @link     https://github.com/mjaschen/phpgeo
9
 */
10
11
namespace Location\Bearing;
12
13
use Location\Coordinate;
14
15
/**
16
 * Calculation of bearing between two points using a
17
 * simple spherical model of the earth.
18
 *
19
 * @author   Marcus Jaschen <[email protected]>
20
 * @license  https://opensource.org/licenses/GPL-3.0 GPL
21
 * @link     https://github.com/mjaschen/phpgeo
22
 */
23
class BearingSpherical implements BearingInterface
24
{
25
    /**
26
     * Earth radius in meters.
27
     */
28
    const EARTH_RADIUS = 6371009;
29
30
    /**
31
     * This method calculates the initial bearing between the
32
     * two points.
33
     *
34
     * @param \Location\Coordinate $point1
35
     * @param \Location\Coordinate $point2
36
     *
37
     * @return float Bearing Angle
38
     */
39
    public function calculateBearing(Coordinate $point1, Coordinate $point2)
40
    {
41
        $lat1 = deg2rad($point1->getLat());
42
        $lat2 = deg2rad($point2->getLat());
43
        $lng1 = deg2rad($point1->getLng());
44
        $lng2 = deg2rad($point2->getLng());
45
46
        $y = sin($lng2 - $lng1) * cos($lat2);
47
        $x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($lng2 - $lng1);
48
49
        $bearing = rad2deg(atan2($y, $x));
50
51
        if ($bearing < 0) {
52
            $bearing = fmod($bearing + 360, 360);
53
        }
54
55
        return $bearing;
56
    }
57
58
    /**
59
     * Calculates the final bearing between the two points.
60
     *
61
     * @param \Location\Coordinate $point1
62
     * @param \Location\Coordinate $point2
63
     *
64
     * @return float
65
     */
66
    public function calculateFinalBearing(Coordinate $point1, Coordinate $point2)
67
    {
68
        $initialBearing = $this->calculateBearing($point2, $point1);
69
70
        return fmod($initialBearing + 180, 360);
71
    }
72
73
    /**
74
     * Calculates a destination point for the given point, bearing angle,
75
     * and distance.
76
     *
77
     * @param \Location\Coordinate $point
78
     * @param float $bearing the bearing angle between 0 and 360 degrees
79
     * @param float $distance the distance to the destination point in meters
80
     *
81
     * @return Coordinate
82
     */
83
    public function calculateDestination(Coordinate $point, $bearing, $distance)
84
    {
85
        $D = $distance / static::EARTH_RADIUS;
86
        $B = deg2rad($bearing);
87
        $φ = deg2rad($point->getLat());
88
        $λ = deg2rad($point->getLng());
89
90
        $Φ = asin(sin($φ) * cos($D) + cos($φ) * sin($D) * cos($B));
91
        $Λ = $λ + atan2(sin($B) * sin($D) * cos($φ), cos($D) - sin($φ) * sin($φ));
92
93
        return new Coordinate(rad2deg($Φ), rad2deg($Λ));
94
    }
95
}
96