Coordinate   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Importance

Changes 0
Metric Value
wmc 16
lcom 0
cbo 5
dl 0
loc 180
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 4
A getLat() 0 4 1
A getLng() 0 4 1
A getPoints() 0 4 1
A getEllipsoid() 0 4 1
A getDistance() 0 4 1
A getCardinalDirectionDistances() 0 7 1
A hasSameLocation() 0 4 1
A format() 0 4 1
A isValidLatitude() 0 4 1
A isValidLongitude() 0 4 1
A isNumericInBounds() 0 4 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Location;
6
7
use InvalidArgumentException;
8
use Location\CardinalDirection\CardinalDirectionDistances;
9
use Location\CardinalDirection\CardinalDirectionDistancesCalculator;
10
use Location\Distance\DistanceInterface;
11
use Location\Distance\Haversine;
12
use Location\Formatter\Coordinate\FormatterInterface;
13
14
/**
15
 * Coordinate Implementation
16
 *
17
 * @author Marcus Jaschen <[email protected]>
18
 */
19
class Coordinate implements GeometryInterface
20
{
21
    /**
22
     * @var float
23
     */
24
    protected $lat;
25
26
    /**
27
     * @var float
28
     */
29
    protected $lng;
30
31
    /**
32
     * @var Ellipsoid
33
     */
34
    protected $ellipsoid;
35
36
    /**
37
     * @param float $lat -90.0 .. +90.0
38
     * @param float $lng -180.0 .. +180.0
39
     * @param Ellipsoid $ellipsoid if omitted, WGS-84 is used
40
     *
41
     * @throws \InvalidArgumentException
42
     */
43
    public function __construct(float $lat, float $lng, Ellipsoid $ellipsoid = null)
44
    {
45
        if (! $this->isValidLatitude($lat)) {
46
            throw new InvalidArgumentException('Latitude value must be numeric -90.0 .. +90.0 (given: ' . $lat . ')');
47
        }
48
49
        if (! $this->isValidLongitude($lng)) {
50
            throw new InvalidArgumentException(
51
                'Longitude value must be numeric -180.0 .. +180.0 (given: ' . $lng . ')'
52
            );
53
        }
54
55
        $this->lat = $lat;
56
        $this->lng = $lng;
57
58
        if ($ellipsoid instanceof Ellipsoid) {
59
            $this->ellipsoid = $ellipsoid;
60
61
            return;
62
        }
63
64
        $this->ellipsoid = Ellipsoid::createDefault();
65
    }
66
67
    /**
68
     * @return float
69
     */
70
    public function getLat(): float
71
    {
72
        return $this->lat;
73
    }
74
75
    /**
76
     * @return float
77
     */
78
    public function getLng(): float
79
    {
80
        return $this->lng;
81
    }
82
83
    /**
84
     * Returns an array containing the point
85
     *
86
     * @return Coordinate[]
87
     */
88
    public function getPoints(): array
89
    {
90
        return [$this];
91
    }
92
93
    /**
94
     * @return Ellipsoid
95
     */
96
    public function getEllipsoid(): Ellipsoid
97
    {
98
        return $this->ellipsoid;
99
    }
100
101
    /**
102
     * Calculates the distance between the given coordinate
103
     * and this coordinate.
104
     *
105
     * @param Coordinate $coordinate
106
     * @param DistanceInterface $calculator instance of distance calculation class
107
     *
108
     * @return float
109
     */
110
    public function getDistance(Coordinate $coordinate, DistanceInterface $calculator): float
111
    {
112
        return $calculator->getDistance($this, $coordinate);
113
    }
114
115
    /**
116
     * Calculates the cardinal direction distances from this coordinate
117
     * to given coordinate.
118
     *
119
     * @param Coordinate $coordinate
120
     * @param DistanceInterface $calculator instance of distance calculation class
121
     *
122
     * @return CardinalDirectionDistances
123
     */
124
    public function getCardinalDirectionDistances(
125
        Coordinate $coordinate,
126
        DistanceInterface $calculator
127
    ): CardinalDirectionDistances {
128
        return (new CardinalDirectionDistancesCalculator())
129
            ->getCardinalDirectionDistances($this, $coordinate, $calculator);
130
    }
131
132
    /**
133
     * Checks if two points describe the same location within an allowed distance.
134
     *
135
     * Uses the Haversine distance calculator for distance calculation as it's
136
     * precise enough for short-distance calculations.
137
     *
138
     * @param Coordinate $coordinate
139
     * @param float $allowedDistance the default value is one millimeter.
140
     *
141
     * @return bool
142
     *
143
     * @see Haversine
144
     */
145
    public function hasSameLocation(Coordinate $coordinate, float $allowedDistance = .001): bool
146
    {
147
        return $this->getDistance($coordinate, new Haversine()) <= $allowedDistance;
148
    }
149
150
    /**
151
     * @param FormatterInterface $formatter
152
     *
153
     * @return mixed
154
     */
155
    public function format(FormatterInterface $formatter)
156
    {
157
        return $formatter->format($this);
158
    }
159
160
    /**
161
     * Validates latitude
162
     *
163
     * @param float $latitude
164
     *
165
     * @return bool
166
     */
167
    protected function isValidLatitude(float $latitude): bool
168
    {
169
        return $this->isNumericInBounds($latitude, -90.0, 90.0);
170
    }
171
172
    /**
173
     * Validates longitude
174
     *
175
     * @param float $longitude
176
     *
177
     * @return bool
178
     */
179
    protected function isValidLongitude(float $longitude): bool
180
    {
181
        return $this->isNumericInBounds($longitude, -180.0, 180.0);
182
    }
183
184
    /**
185
     * Checks if the given value is (1) numeric, and (2) between lower
186
     * and upper bounds (including the bounds values).
187
     *
188
     * @param float $value
189
     * @param float $lower
190
     * @param float $upper
191
     *
192
     * @return bool
193
     */
194
    protected function isNumericInBounds(float $value, float $lower, float $upper): bool
195
    {
196
        return !($value < $lower || $value > $upper);
197
    }
198
}
199