forked from DataValues/Geo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGlobeMath.php
More file actions
117 lines (100 loc) · 3.04 KB
/
GlobeMath.php
File metadata and controls
117 lines (100 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
declare( strict_types = 1 );
namespace DataValues\Geo;
use DataValues\Geo\Values\GlobeCoordinateValue;
use DataValues\Geo\Values\LatLongValue;
/**
* Logical and mathematical helper functions for normalizations and calculations with
* GlobeCoordinateValue objects.
*
* @since 0.2
* @api
*
* @license GPL-2.0-or-later
* @author Thiemo Kreuz
*/
class GlobeMath {
/**
* @todo Move this constant next to GlobeCoordinateValue::GLOBE_EARTH?
*/
public const GLOBE_MOON = 'http://www.wikidata.org/entity/Q405';
/**
* @param string|null $globe IRI of a globe.
*
* @return string Normalized IRI, defaults to 'http://www.wikidata.org/entity/Q2'.
*/
public function normalizeGlobe( ?string $globe ) {
if ( !is_string( $globe ) || $globe === '' ) {
return GlobeCoordinateValue::GLOBE_EARTH;
}
return $globe;
}
/**
* Normalizes latitude to [-90°..+90°]. Normalizes longitude to [-180°..+180°[ on Earth and
* Moon and to [0°..+360°[ on all other globes.
* @see http://planetarynames.wr.usgs.gov/TargetCoordinates
*
* @param GlobeCoordinateValue $value
*
* @return GlobeCoordinateValue
*/
public function normalizeGlobeCoordinate( GlobeCoordinateValue $value ): GlobeCoordinateValue {
return new GlobeCoordinateValue(
$this->normalizeGlobeLatLong( $value->getLatLong(), $value->getGlobe() ),
$value->getPrecision(),
$value->getGlobe()
);
}
/**
* @param LatLongValue $value
* @param string|null $globe
*
* @return LatLongValue
*/
public function normalizeGlobeLatLong( LatLongValue $value, ?string $globe = null ): LatLongValue {
$minimumLongitude = match ( $this->normalizeGlobe( $globe ) ) {
GlobeCoordinateValue::GLOBE_EARTH, self::GLOBE_MOON => -180,
default => 0,
};
return $this->normalizeLatLong( $value, $minimumLongitude );
}
/**
* @param LatLongValue $value
* @param float $minimumLongitude
*
* @return LatLongValue
*/
public function normalizeLatLong( LatLongValue $value, float $minimumLongitude = -180.0 ): LatLongValue {
$lon = $this->getNormalizedLongitude( $value->getLongitude(), $minimumLongitude );
$lat = $value->getLatitude();
if ( $lat >= 270 ) {
// Same side of the globe, on the southern hemisphere.
$lat -= 360;
} elseif ( $lat <= -270 ) {
// Same side of the globe, on the northern hemisphere.
$lat += 360;
} elseif ( $lat > 90 ) {
// Other side of the globe
$lat = 180 - $lat;
$lon += $lon - 180 >= $minimumLongitude ? -180 : 180;
} elseif ( $lat < -90 ) {
// Other side of the globe
$lat = -180 - $lat;
$lon += $lon - 180 >= $minimumLongitude ? -180 : 180;
}
// North/south pole
if ( abs( $lat ) === 90.0 ) {
$lon = 0;
}
return new LatLongValue( $lat, $lon );
}
private function getNormalizedLongitude( float $longitude, float $minimumLongitude ): float {
// Normalize to [-180°..+180°[ on Earth/Moon, [0°..+360°[ on other globes.
if ( $longitude >= $minimumLongitude + 360 ) {
$longitude -= 360;
} elseif ( $longitude < $minimumLongitude ) {
$longitude += 360;
}
return $longitude;
}
}