Completed
Push — master ( d63616...511dbe )
by Tobias
02:09
created

Coordinate::toDecimalDegrees()   C

Complexity

Conditions 14
Paths 18

Size

Total Lines 60
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 14.0089

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 60
ccs 27
cts 28
cp 0.9643
rs 6.325
cc 14
eloc 32
nc 18
nop 1
crap 14.0089

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Geotools library.
5
 *
6
 * (c) Antoine Corcy <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace League\Geotools\Coordinate;
13
14
use Geocoder\Location;
15
use League\Geotools\Exception\InvalidArgumentException;
16
17
/**
18
 * Coordinate class
19
 *
20
 * @author Antoine Corcy <[email protected]>
21
 */
22
class Coordinate implements CoordinateInterface, \JsonSerializable
23
{
24
    /**
25
     * The latitude of the coordinate.
26
     *
27
     * @var double
28
     */
29
    protected $latitude;
30
31
    /**
32
     * The longitude of the coordinate.
33
     *
34
     * @var double
35
     */
36
    protected $longitude;
37
38
    /**
39
     * The selected ellipsoid.
40
     *
41
    * @var Ellipsoid
42
    */
43
    protected $ellipsoid;
44
45
46
    /**
47
     * The precision to use to compare big numbers
48
     *
49
     * @var integer
50
     */
51
    private $precision = 8;
52
53
    /**
54
     * Set the latitude and the longitude of the coordinates into an selected ellipsoid.
55
     *
56
     * @param Location|array|string         $coordinates The coordinates.
57
     * @param Ellipsoid                    $ellipsoid   The selected ellipsoid (WGS84 by default).
58
     *
59
     * @throws InvalidArgumentException
60
     */
61 253
    public function __construct($coordinates, Ellipsoid $ellipsoid = null)
62
    {
63 253
        if ($coordinates instanceof Location) {
64 37
            if (null !== $locationCoordinates = $coordinates->getCoordinates()) {
65 4
                $this->setLatitude($locationCoordinates->getLatitude());
66 37
                $this->setLongitude($locationCoordinates->getLongitude());
67
            }
68 216
        } elseif (is_array($coordinates) && 2 === count($coordinates)) {
69 63
            $this->setLatitude($coordinates[0]);
70 63
            $this->setLongitude($coordinates[1]);
71 159
        } elseif (is_string($coordinates)) {
72 154
            $this->setFromString($coordinates);
73
        } else {
74 5
            throw new InvalidArgumentException(
75 5
                'It should be a string, an array or a class which implements Geocoder\Model\Address !'
76
            );
77
        }
78
79 222
        $this->ellipsoid = $ellipsoid ?: Ellipsoid::createFromName(Ellipsoid::WGS84);
80 222
    }
81
82
    /**
83
     * {@inheritDoc}
84
     */
85 201
    public function normalizeLatitude($latitude)
86
    {
87 201
        return (double) max(-90, min(90, $latitude));
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93 207
    public function normalizeLongitude($longitude)
94
    {
95 207
        if (180 === $longitude % 360) {
96 3
            return 180.0;
97
        }
98
99 204
        $mod       = fmod($longitude, 360);
100 204
        $longitude = $mod < -180 ? $mod + 360 : ($mod > 180 ? $mod - 360 : $mod);
101
102 204
        return (double) $longitude;
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 198
    public function setLatitude($latitude)
109
    {
110 198
        $this->latitude = $this->normalizeLatitude($latitude);
111 198
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116 197
    public function getLatitude()
117
    {
118 197
        return $this->latitude;
119
    }
120
121
    /**
122
     * {@inheritDoc}
123
     */
124 198
    public function setLongitude($longitude)
125
    {
126 198
        $this->longitude = $this->normalizeLongitude($longitude);
127 198
    }
128
129
    /**
130
     * {@inheritDoc}
131
     */
132 197
    public function getLongitude()
133
    {
134 197
        return $this->longitude;
135
    }
136
137
    /**
138
     * {@inheritDoc}
139
     */
140 108
    public function getEllipsoid()
141
    {
142 108
        return $this->ellipsoid;
143
    }
144
145
    /**
146
     * Creates a valid and acceptable geographic coordinates.
147
     *
148
     * @param string $coordinates
149
     *
150
     * @throws InvalidArgumentException
151
     */
152 157
    public function setFromString($coordinates)
153
    {
154 157
        if (!is_string($coordinates)) {
155 1
            throw new InvalidArgumentException('The given coordinates should be a string !');
156
        }
157
158
        try {
159 156
            $inDecimalDegree = $this->toDecimalDegrees($coordinates);
160 129
            $this->setLatitude($inDecimalDegree[0]);
161 129
            $this->setLongitude($inDecimalDegree[1]);
162 27
        } catch (InvalidArgumentException $e) {
163 27
            throw $e;
164
        }
165 129
    }
166
167
    /**
168
     * @return integer
169
     */
170 3
    public function getPrecision()
171
    {
172 3
        return $this->precision;
173
    }
174
175
    /**
176
     * @param  integer $precision
177
     * @return $this
178
     */
179
    public function setPrecision($precision)
180
    {
181
        $this->precision = $precision;
182
183
        return $this;
184
    }
185
186
187
    /**
188
     * Converts a valid and acceptable geographic coordinates to decimal degrees coordinate.
189
     *
190
     * @param string $coordinates A valid and acceptable geographic coordinates.
191
     *
192
     * @return array An array of coordinate in decimal degree.
193
     *
194
     * @throws InvalidArgumentException
195
     *
196
     * @see http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
197
     */
198 156
    private function toDecimalDegrees($coordinates)
199
    {
200
        // 40.446195, -79.948862
201 156
        if (preg_match('/(\-?[0-9]{1,2}\.?\d*)[, ] ?(\-?[0-9]{1,3}\.?\d*)$/', $coordinates, $match)) {
202 45
            return array($match[1], $match[2]);
203
        }
204
205
        // 40° 26.7717, -79° 56.93172
206 111
        if (preg_match('/(\-?[0-9]{1,2})\D+([0-9]{1,2}\.?\d*)[, ] ?(\-?[0-9]{1,3})\D+([0-9]{1,2}\.?\d*)$/i',
207 111
            $coordinates, $match)) {
208
            return array(
209 55
                $match[1] < 0
210
                    ? $match[1] - $match[2] / 60
211 55
                    : $match[1] + $match[2] / 60,
212 55
                $match[3] < 0
213 55
                    ? $match[3] - $match[4] / 60
214 55
                    : $match[3] + $match[4] / 60
215
            );
216
        }
217
218
        // 40.446195N 79.948862W
219 94
        if (preg_match('/([0-9]{1,2}\.?\d*)\D*([ns]{1})[, ] ?([0-9]{1,3}\.?\d*)\D*([we]{1})$/i', $coordinates, $match)) {
220
            return array(
221 6
                'N' === strtoupper($match[2]) ? $match[1] : -$match[1],
222 6
                'E' === strtoupper($match[4]) ? $match[3] : -$match[3]
223
            );
224
        }
225
226
        // 40°26.7717S 79°56.93172E
227
        // 25°59.86′N,21°09.81′W
228 88
        if (preg_match('/([0-9]{1,2})\D+([0-9]{1,2}\.?\d*)\D*([ns]{1})[, ] ?([0-9]{1,3})\D+([0-9]{1,2}\.?\d*)\D*([we]{1})$/i',
229 88
            $coordinates, $match)) {
230 3
            $latitude  = $match[1] + $match[2] / 60;
231 3
            $longitude = $match[4] + $match[5] / 60;
232
233
            return array(
234 3
                'N' === strtoupper($match[3]) ? $latitude  : -$latitude,
235 3
                'E' === strtoupper($match[6]) ? $longitude : -$longitude
236
            );
237
        }
238
239
        // 40:26:46N, 079:56:55W
240
        // 40:26:46.302N 079:56:55.903W
241
        // 40°26′47″N 079°58′36″W
242
        // 40d 26′ 47″ N 079d 58′ 36″ W
243 85
        if (preg_match('/([0-9]{1,2})\D+([0-9]{1,2})\D+([0-9]{1,2}\.?\d*)\D*([ns]{1})[, ] ?([0-9]{1,3})\D+([0-9]{1,2})\D+([0-9]{1,2}\.?\d*)\D*([we]{1})$/i',
244 85
            $coordinates, $match)) {
245 58
            $latitude  = $match[1] + ($match[2] * 60 + $match[3]) / 3600;
246 58
            $longitude = $match[5] + ($match[6] * 60 + $match[7]) / 3600;
247
248
            return array(
249 58
                'N' === strtoupper($match[4]) ? $latitude  : -$latitude,
250 58
                'E' === strtoupper($match[8]) ? $longitude : -$longitude
251
            );
252
        }
253
254 27
        throw new InvalidArgumentException(
255 27
            'It should be a valid and acceptable ways to write geographic coordinates !'
256
        );
257
    }
258
259
    /**
260
     * {@inheritDoc}
261
     */
262
    public function jsonSerialize()
263
    {
264
        return [$this->latitude, $this->longitude];
265
    }
266
267
    /**
268
     * Returns a boolean determining coordinates equality
269
     * @param  Coordinate  $coordinate
270
     * @return boolean
271
     */
272 3
    public function isEqual(Coordinate $coordinate) {
273 3
        return bccomp($this->latitude, $coordinate->getLatitude(), $this->getPrecision()) === 0 && bccomp($this->longitude, $coordinate->getLongitude(), $this->getPrecision()) === 0;
274
    }
275
}
276