BearingSpherical   A
last analyzed

Complexity

Total Complexity 4

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
wmc 4
lcom 0
cbo 1
dl 0
loc 74
rs 10
c 0
b 0
f 0

3 Methods

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