TrackPoint   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 0
Metric Value
wmc 15
lcom 2
cbo 2
dl 0
loc 223
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 2
A addExtension() 0 4 1
A with() 0 15 1
A elevation() 0 4 1
A extensions() 0 4 1
A hasExtension() 0 4 1
A extension() 0 8 2
A latitude() 0 4 1
A longitude() 0 4 1
A dateTime() 0 4 1
A distanceFromPoint() 0 21 1
A speed() 0 15 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace SportTrackerConnector\Core\Workout;
6
7
use Assert\Assertion;
8
use SportTrackerConnector\Core\Workout\Extension\ExtensionInterface;
9
10
/**
11
 * A point in a track.
12
 */
13
final class TrackPoint
14
{
15
    /**
16
     * Latitude of the point.
17
     *
18
     * @var float
19
     */
20
    private $latitude;
21
22
    /**
23
     * Longitude of the point.
24
     *
25
     * @var float
26
     */
27
    private $longitude;
28
29
    /**
30
     * Elevation of the point.
31
     *
32
     * @var float
33
     */
34
    private $elevation;
35
36
    /**
37
     * The time for the point.
38
     *
39
     * @var \DateTimeImmutable
40
     */
41
    private $dateTime;
42
43
    /**
44
     * Array of extensions.
45
     *
46
     * @var ExtensionInterface[]
47
     */
48
    private $extensions = array();
49
50
    /**
51
     * @param float $latitude The latitude.
52
     * @param float $longitude The longitude.
53
     * @param \DateTimeImmutable $dateTime The date and time of the point.
54
     * @param float|null $elevation
55
     * @param array $extensions
56
     */
57
    private function __construct(
58
        ?float $latitude,
59
        ?float $longitude,
60
        \DateTimeImmutable $dateTime,
61
        ?float $elevation,
62
        array $extensions = []
63
    ) {
64
        $this->latitude = $latitude;
65
        $this->longitude = $longitude;
66
        $this->dateTime = $dateTime;
67
        $this->elevation = $elevation;
68
69
        foreach ($extensions as $extension) {
70
            $this->addExtension($extension);
71
        }
72
    }
73
74
    /**
75
     * Add an extension to the workout.
76
     *
77
     * @param ExtensionInterface $extension The extension to add.
78
     */
79
    private function addExtension(ExtensionInterface $extension)
80
    {
81
        $this->extensions[$extension::ID()] = $extension;
82
    }
83
84
    /**
85
     * @param float|null $latitude
86
     * @param float|null $longitude
87
     * @param \DateTimeImmutable $dateTime
88
     * @param float|null $elevation
89
     * @param array $extensions
90
     * @return TrackPoint
91
     */
92
    public static function with(
93
        ?float $latitude,
94
        ?float $longitude,
95
        \DateTimeImmutable $dateTime,
96
        ?float $elevation = null,
97
        array $extensions = []
98
    ): TrackPoint {
99
        Assertion::greaterOrEqualThan($latitude, -180);
100
        Assertion::greaterOrEqualThan($longitude, -180);
101
        Assertion::lessOrEqualThan($latitude, 180);
102
        Assertion::lessOrEqualThan($longitude, 180);
103
        Assertion::allIsInstanceOf($extensions, ExtensionInterface::class);
104
105
        return new static($latitude, $longitude, $dateTime, $elevation, $extensions);
106
    }
107
108
    /**
109
     * Get the elevation.
110
     *
111
     * @return float
112
     */
113
    public function elevation(): float
114
    {
115
        return $this->elevation;
116
    }
117
118
    /**
119
     * Get the extensions.
120
     *
121
     * @return ExtensionInterface[]
122
     */
123
    public function extensions(): array
124
    {
125
        return array_values($this->extensions);
126
    }
127
128
129
    /**
130
     * Check if an extension is present.
131
     *
132
     * @param string $idExtension The ID of the extension.
133
     * @return boolean
134
     */
135
    public function hasExtension(string $idExtension): bool
136
    {
137
        return array_key_exists($idExtension, $this->extensions);
138
    }
139
140
    /**
141
     * Get an extension by ID.
142
     *
143
     * @param string $idExtension The ID of the extension.
144
     * @return ExtensionInterface
145
     * @throws \OutOfBoundsException If the extension is not found.
146
     */
147
    public function extension($idExtension): ExtensionInterface
148
    {
149
        if ($this->hasExtension($idExtension) !== true) {
150
            throw new \OutOfBoundsException(sprintf('Extension "%s" not found.', $idExtension));
151
        }
152
153
        return $this->extensions[$idExtension];
154
    }
155
156
    /**
157
     * Get the latitude.
158
     *
159
     * @return float
160
     */
161
    public function latitude(): ?float
162
    {
163
        return $this->latitude;
164
    }
165
166
    /**
167
     * Get the longitude.
168
     *
169
     * @return float
170
     */
171
    public function longitude(): ?float
172
    {
173
        return $this->longitude;
174
    }
175
176
    /**
177
     * Get the date time of the point.
178
     *
179
     * @return \DateTimeImmutable
180
     */
181
    public function dateTime(): \DateTimeImmutable
182
    {
183
        return $this->dateTime;
184
    }
185
186
    /**
187
     * Get the distance between this point and another point in meters.
188
     *
189
     * @param TrackPoint $trackPoint The other point.
190
     * @return float The distance in meters.
191
     */
192
    public function distanceFromPoint(TrackPoint $trackPoint): float
193
    {
194
        $earthRadius = 6371000;
195
196
        $latFrom = deg2rad($this->latitude());
197
        $lonFrom = deg2rad($this->longitude());
198
        $latTo = deg2rad($trackPoint->latitude());
199
        $lonTo = deg2rad($trackPoint->longitude());
200
201
        $latDelta = $latTo - $latFrom;
202
        $lonDelta = $lonTo - $lonFrom;
203
204
        $angle = 2 * asin(
205
                sqrt(
206
                    pow(sin($latDelta / 2), 2) +
207
                    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)
208
                )
209
            );
210
211
        return $angle * $earthRadius;
212
    }
213
214
    /**
215
     * Get the speed between this point and another point in km/h.
216
     *
217
     * @param TrackPoint $trackPoint The other point.
218
     * @return float
219
     */
220
    public function speed(TrackPoint $trackPoint): float
221
    {
222
        $start = $this->dateTime();
223
        $end = $trackPoint->dateTime();
224
        $dateDiff = $start->diff($end);
225
        $secondsDifference = ($dateDiff->days * 86400) + ($dateDiff->h * 3600) + ($dateDiff->i * 60) + $dateDiff->s;
226
227
        if ($secondsDifference === 0) {
228
            return 0.0;
229
        }
230
231
        $distance = $this->distanceFromPoint($trackPoint);
232
233
        return ($distance / $secondsDifference) * 3.6;
234
    }
235
}
236