DistanceCalculator   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 109
ccs 32
cts 32
cp 1
rs 10
c 1
b 0
f 0
wmc 5

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A calculateRadianLength() 0 16 1
A getRadianValue() 0 3 1
A calculate() 0 8 1
A calculateHaversineDistance() 0 20 1
1
<?php
2
3
namespace ZeroConfig\GeoDistance;
4
5
use Measurements\Exceptions\UnitException;
6
use Measurements\Measurement;
7
use Measurements\Quantities\Length;
8
use Measurements\Units\UnitAngle;
9
use Measurements\Units\UnitLength;
10
use ZeroConfig\GeoDistance\Sphere\SphereInterface;
11
12
/**
13
 * @see https://en.wikipedia.org/wiki/Haversine_formula
14
 */
15
class DistanceCalculator implements DistanceCalculatorInterface
16
{
17
    /** @var SphereInterface */
18
    private $sphere;
19
20
    /**
21
     * Constructor.
22
     *
23
     * @param SphereInterface $sphere
24
     */
25 1
    public function __construct(SphereInterface $sphere)
26
    {
27 1
        $this->sphere = $sphere;
28 1
    }
29
30
    /**
31
     * Calculate the distance between two positions.
32
     *
33
     * @param PositionInterface $start
34
     * @param PositionInterface $end
35
     *
36
     * @return Measurement
37
     * @throws UnitException UnitException When part of the distance is
38
     *   incalculable.
39
     */
40 1
    public function calculate(
41
        PositionInterface $start,
42
        PositionInterface $end
43
    ): Measurement {
44 1
        return (new Length(
45 1
            $this->calculateRadianLength($start, $end),
46 1
            UnitLength::meters()
47 1
        ))->multiplyBy($this->sphere->getRadius());
48
    }
49
50
    /**
51
     * Calculate the radian length between start and end.
52
     *
53
     * @param PositionInterface $start
54
     * @param PositionInterface $end
55
     *
56
     * @return float
57
     * @throws UnitException UnitException When part of the length is
58
     *  incalculable.
59
     */
60 1
    private function calculateRadianLength(
61
        PositionInterface $start,
62
        PositionInterface $end
63
    ): float {
64 1
        return $this->calculateHaversineDistance(
65 1
            $this->getRadianValue($start->getLatitude()),
66 1
            $this->getRadianValue($end->getLatitude()),
67 1
            $this->getRadianValue(
68
                $start
69 1
                    ->getLatitude()
70 1
                    ->subtract($end->getLatitude())
71
            ),
72 1
            $this->getRadianValue(
73
                $start
74 1
                    ->getLongitude()
75 1
                    ->subtract($end->getLongitude())
76
            )
77
        );
78
    }
79
80
    /**
81
     * Calculate the haversine distance.
82
     *
83
     * @param float $startLatitude
84
     * @param float $endLatitude
85
     * @param float $deltaLatitude
86
     * @param float $deltaLongitude
87
     *
88
     * @return float
89
     */
90 1
    private function calculateHaversineDistance(
91
        float $startLatitude,
92
        float $endLatitude,
93
        float $deltaLatitude,
94
        float $deltaLongitude
95
    ): float {
96 1
        return asin(
97 1
            sqrt(
98 1
                pow(
99 1
                    sin($deltaLatitude * 0.5),
100 1
                    2
101
                )
102 1
                + cos($startLatitude)
103 1
                * cos($endLatitude)
104 1
                * pow(
105 1
                    sin($deltaLongitude * 0.5),
106 1
                    2
107
                )
108
            )
109 1
        ) * 2;
110
    }
111
112
    /**
113
     * Get the radion value for the supplied angle.
114
     *
115
     * @param Measurement $angle
116
     *
117
     * @return float
118
     * @throws UnitException UnitException When part of the angle is
119
     *   incalculable.
120
     */
121 1
    private function getRadianValue(Measurement $angle): float
122
    {
123 1
        return $angle->convertTo(UnitAngle::radians())->value();
124
    }
125
}
126