Completed
Push — mv ( 2424da...13ee4c )
by Jeroen De
06:33 queued 01:32
created

MapsGeoFunctions::calculateDistance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 20
cts 20
cp 1
rs 9.424
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
// The approximate radius of the earth in meters, according to http://en.wikipedia.org/wiki/Earth_radius.
4
use DataValues\Geo\Values\LatLongValue;
5
6 1
define( 'Maps_EARTH_RADIUS', 6371000 );
7
8
/**
9
 * Static class containing geographical functions.
10
 *
11
 * @since 0.6
12
 *
13
 * @licence GNU GPL v2+
14
 * @author Jeroen De Dauw < [email protected] >
15
 * @author Pnelnik
16
 * @author Matěj Grabovský
17
 */
18
final class MapsGeoFunctions {
19
20
	/**
21
	 * Returns the geographical distance between two coordinates.
22
	 * See http://en.wikipedia.org/wiki/Geographical_distance
23
	 *
24
	 * @since 2.0
25
	 *
26
	 * @param LatLongValue $start
27
	 * @param LatLongValue $end
28
	 *
29
	 * @return float Distance in m.
30
	 */
31 2
	public static function calculateDistance( LatLongValue $start, LatLongValue $end ) {
32 2
		$northRad1 = deg2rad( $start->getLatitude() );
33 2
		$eastRad1 = deg2rad( $start->getLongitude() );
34
35 2
		$cosNorth1 = cos( $northRad1 );
36 2
		$cosEast1 = cos( $eastRad1 );
37
38 2
		$sinNorth1 = sin( $northRad1 );
39 2
		$sinEast1 = sin( $eastRad1 );
40
41 2
		$northRad2 = deg2rad( $end->getLatitude() );
42 2
		$eastRad2 = deg2rad( $end->getLongitude() );
43
44 2
		$cosNorth2 = cos( $northRad2 );
45 2
		$cosEast2 = cos( $eastRad2 );
46
47 2
		$sinNorth2 = sin( $northRad2 );
48 2
		$sinEast2 = sin( $eastRad2 );
49
50 2
		$term1 = $cosNorth1 * $sinEast1 - $cosNorth2 * $sinEast2;
51 2
		$term2 = $cosNorth1 * $cosEast1 - $cosNorth2 * $cosEast2;
52 2
		$term3 = $sinNorth1 - $sinNorth2;
53
54 2
		$distThruSquared = $term1 * $term1 + $term2 * $term2 + $term3 * $term3;
55
56 2
		$distance = 2 * Maps_EARTH_RADIUS * asin( sqrt( $distThruSquared ) / 2 );
57
58 2
		assert( $distance >= 0 );
59
60 2
		return $distance;
61
	}
62
63
	/**
64
	 * Finds a destination given a starting location, bearing and distance.
65
	 *
66
	 * @since 2.0
67
	 *
68
	 * @param LatLongValue $startingCoordinates
69
	 * @param float $bearing The initial bearing in degrees.
70
	 * @param float $distance The distance to travel in km.
71
	 *
72
	 * @return array The destination coordinates, as non-directional floats in an array with lat and lon keys.
73
	 */
74 1
	public static function findDestination( LatLongValue $startingCoordinates, $bearing, $distance ) {
75
		$startingCoordinates = [
76 1
			'lat' => deg2rad( $startingCoordinates->getLatitude() ),
77 1
			'lon' => deg2rad( $startingCoordinates->getLongitude() ),
78
		];
79
80 1
		$radBearing = deg2rad( (float)$bearing );
81 1
		$angularDistance = $distance / Maps_EARTH_RADIUS;
82
83 1
		$lat = asin(
84 1
			sin( $startingCoordinates['lat'] ) * cos( $angularDistance ) + cos( $startingCoordinates['lat'] ) * sin(
85 1
				$angularDistance
86 1
			) * cos( $radBearing )
87
		);
88 1
		$lon = $startingCoordinates['lon'] + atan2(
89 1
				sin( $radBearing ) * sin( $angularDistance ) * cos( $startingCoordinates['lat'] ),
90 1
				cos( $angularDistance ) - sin( $startingCoordinates['lat'] ) * sin( $lat )
91
			);
92
93
		return [
94 1
			'lat' => rad2deg( $lat ),
95 1
			'lon' => rad2deg( $lon )
96
		];
97
	}
98
99
}