Completed
Push — master ( ef8e35...28395c )
by Antoine
05:19
created

Vertex::isOnSameLine()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 8.1426

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 5
cts 7
cp 0.7143
rs 8.2222
c 0
b 0
f 0
cc 7
eloc 10
nc 4
nop 1
crap 8.1426
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\Vertex;
13
14
use League\Geotools\Coordinate\Coordinate;
15
use League\Geotools\Coordinate\CoordinateInterface;
16
use League\Geotools\Coordinate\Ellipsoid;
17
use League\Geotools\CoordinateCouple;
18
use League\Geotools\Geotools;
19
20
/**
21
 * Vertex class
22
 *
23
 * @author Antoine Corcy <[email protected]>
24
 */
25
class Vertex implements VertexInterface
26
{
27
    use CoordinateCouple;
28
29
    /**
30
     * @var double
31
     */
32
    protected $gradient;
33
34
    /**
35
     * @var double
36
     */
37
    protected $ordinateIntercept;
38
39
    /**
40
     * @var integer
41
     */
42
    private $precision = 8;
43
44
    /**
45
     * {@inheritDoc}
46
     */
47 54
    public function setFrom(CoordinateInterface $from)
48
    {
49 54
        $this->from = $from;
50
51 54
        if (empty($this->to) || ($this->to->getLatitude() - $this->from->getLatitude() === 0)) {
52 54
            return $this;
53
        }
54
55
        $this->gradient = ($this->to->getLongitude() - $this->from->getLongitude()) / ($this->to->getLatitude() - $this->from->getLatitude());
56
        $this->ordinateIntercept = $this->from->getLongitude() - $this->from->getLatitude() * $this->gradient;
57
        return $this;
58
    }
59
60
    /**
61
     * {@inheritDoc}
62
     */
63 1
    public function getFrom()
64
    {
65 1
        return $this->from;
66
    }
67
68
    /**
69
     * {@inheritDoc}
70
     */
71 45
    public function setTo(CoordinateInterface $to)
72
    {
73 45
        $this->to = $to;
74
75 45
        if (empty($this->from) || ($this->to->getLatitude() - $this->from->getLatitude() === 0)) {
76 6
            return $this;
77
        }
78
79 39
        $this->gradient = ($this->to->getLongitude() - $this->from->getLongitude()) / ($this->to->getLatitude() - $this->from->getLatitude());
80 39
        $this->ordinateIntercept = $this->from->getLongitude() - $this->from->getLatitude() * $this->gradient;
81
82 39
        return $this;
83
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88 1
    public function getTo()
89
    {
90 1
        return $this->to;
91
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96 5
    public function getGradient()
97
    {
98 5
        return $this->gradient;
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104 2
    public function getOrdinateIntercept()
105
    {
106 2
        return $this->ordinateIntercept;
107
    }
108
109
    /**
110
     * @return integer
111
     */
112 5
    public function getPrecision()
113
    {
114 5
        return $this->precision;
115
    }
116
117
    /**
118
     * @param  integer $precision
119
     * @return $this
120
     */
121
    public function setPrecision($precision)
122
    {
123
        $this->precision = $precision;
124
125
        return $this;
126
    }
127
128
    /**
129
     * Returns the initial bearing from the origin coordinate
130
     * to the destination coordinate in degrees.
131
     *
132
     * @return float The initial bearing in degrees
133
     */
134 14
    public function initialBearing()
135
    {
136 14
        Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
137
138 14
        $latA = deg2rad($this->from->getLatitude());
139 14
        $latB = deg2rad($this->to->getLatitude());
140 14
        $dLng = deg2rad($this->to->getLongitude() - $this->from->getLongitude());
141
142 14
        $y = sin($dLng) * cos($latB);
143 14
        $x = cos($latA) * sin($latB) - sin($latA) * cos($latB) * cos($dLng);
144
145 14
        return (float) (rad2deg(atan2($y, $x)) + 360) % 360;
146
    }
147
148
    /**
149
     * Returns the final bearing from the origin coordinate
150
     * to the destination coordinate in degrees.
151
     *
152
     * @return float The final bearing in degrees
153
     */
154 14
    public function finalBearing()
155
    {
156 14
        Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
157
158 14
        $latA = deg2rad($this->to->getLatitude());
159 14
        $latB = deg2rad($this->from->getLatitude());
160 14
        $dLng = deg2rad($this->from->getLongitude() - $this->to->getLongitude());
161
162 14
        $y = sin($dLng) * cos($latB);
163 14
        $x = cos($latA) * sin($latB) - sin($latA) * cos($latB) * cos($dLng);
164
165 14
        return (float) ((rad2deg(atan2($y, $x)) + 360) % 360 + 180 ) % 360;
166
    }
167
168
    /**
169
     * Returns the initial cardinal point / direction from the origin coordinate to
170
     * the destination coordinate.
171
     * @see http://en.wikipedia.org/wiki/Cardinal_direction
172
     *
173
     * @return string The initial cardinal point / direction
174
     */
175 7
    public function initialCardinal()
176
    {
177 7
        Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
178
179 7
        return Geotools::$cardinalPoints[(integer) round($this->initialBearing() / 22.5)];
180
    }
181
182
    /**
183
     * Returns the final cardinal point / direction from the origin coordinate to
184
     * the destination coordinate.
185
     * @see http://en.wikipedia.org/wiki/Cardinal_direction
186
     *
187
     * @return string The final cardinal point / direction
188
     */
189 7
    public function finalCardinal()
190
    {
191 7
        Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
192
193 7
        return Geotools::$cardinalPoints[(integer) round($this->finalBearing() / 22.5)];
194
    }
195
196
    /**
197
     * Returns the half-way point / coordinate along a great circle
198
     * path between the origin and the destination coordinates.
199
     *
200
     * @return CoordinateInterface
201
     */
202 7
    public function middle()
203
    {
204 7
        Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
205
206 7
        $latA = deg2rad($this->from->getLatitude());
207 7
        $lngA = deg2rad($this->from->getLongitude());
208 7
        $latB = deg2rad($this->to->getLatitude());
209 7
        $lngB = deg2rad($this->to->getLongitude());
210
211 7
        $bx = cos($latB) * cos($lngB - $lngA);
212 7
        $by = cos($latB) * sin($lngB - $lngA);
213
214 7
        $lat3 = rad2deg(atan2(sin($latA) + sin($latB), sqrt((cos($latA) + $bx) * (cos($latA) + $bx) + $by * $by)));
215 7
        $lng3 = rad2deg($lngA + atan2($by, cos($latA) + $bx));
216
217 7
        return new Coordinate([$lat3, $lng3], $this->from->getEllipsoid());
218
    }
219
220
    /**
221
     * Returns the destination point with a given bearing in degrees travelling along a
222
     * (shortest distance) great circle arc and a distance in meters.
223
     *
224
     * @param integer $bearing  The bearing of the origin in degrees.
225
     * @param integer $distance The distance from the origin in meters.
226
     *
227
     * @return CoordinateInterface
228
     */
229 9
    public function destination($bearing, $distance)
230
    {
231 9
        $lat = deg2rad($this->from->getLatitude());
232 9
        $lng = deg2rad($this->from->getLongitude());
233
234 9
        $bearing = deg2rad($bearing);
235
236 9
        $endLat = asin(sin($lat) * cos($distance / $this->from->getEllipsoid()->getA()) + cos($lat) *
237 9
            sin($distance / $this->from->getEllipsoid()->getA()) * cos($bearing));
238 9
        $endLon = $lng + atan2(sin($bearing) * sin($distance / $this->from->getEllipsoid()->getA()) * cos($lat),
239 9
            cos($distance / $this->from->getEllipsoid()->getA()) - sin($lat) * sin($endLat));
240
241 9
        return new Coordinate([rad2deg($endLat), rad2deg($endLon)], $this->from->getEllipsoid());
242
    }
243
244
    /**
245
     * Returns true if the vertex passed on argument is on the same line as this object
246
     *
247
     * @param  Vertex  $vertex The vertex to compare
248
     * @return boolean
249
     */
250 5
    public function isOnSameLine(Vertex $vertex) {
251 5
        if (is_null($this->getGradient()) && is_null($vertex->getGradient()) && $this->from->getLongitude() == $vertex->getFrom()->getLongitude()) {
252
            return true;
253 5
        } elseif (!is_null($this->getGradient()) && !is_null($vertex->getGradient())) {
254
            return (
255 5
                bccomp($this->getGradient(), $vertex->getGradient(), $this->getPrecision()) === 0
256
                &&
257 5
                bccomp($this->getOrdinateIntercept(), $vertex->getOrdinateIntercept(), $this->getPrecision()) ===0
258
            );
259
        } else {
260
            return false;
261
        }
262
    }
263
264
    /**
265
     * Returns the other coordinate who is not the coordinate passed on argument
266
     * @param  CoordinateInterface $coordinate
267
     * @return null|Coordinate
268
     */
269 3
    public function getOtherCoordinate(CoordinateInterface $coordinate) {
270 3
        if ($coordinate->isEqual($this->from)) {
271 1
            return $this->to;
272 2
        } else if ($coordinate->isEqual($this->to)) {
273 1
            return $this->from;
274
        }
275 1
        return null;
276
    }
277
278
}
279