Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
42.11% covered (danger)
42.11%
24 / 57
90.00% covered (success)
90.00%
9 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Globe
42.11% covered (danger)
42.11%
24 / 57
90.00% covered (success)
90.00%
9 / 10
65.68
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getData
8.33% covered (danger)
8.33%
3 / 36
0.00% covered (danger)
0.00%
0 / 1
5.08
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRadius
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMinLongitude
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMaxLongitude
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEastSign
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isKnown
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 equalsTo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 coordinatesAreValid
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3namespace GeoData;
4
5/**
6 * Immutable representation of a celestial body
7 */
8class Globe {
9
10    public const EARTH = 'earth';
11
12    private string $name;
13
14    /** @var float|null */
15    private $radius;
16
17    /** @var float Defaults to -360 for unknown globes, or to 0 for known globes */
18    private $minLon = -360;
19
20    /** @var float Defaults to +360 for unknown globes */
21    private $maxLon = 360;
22
23    /** @var int Sign for values going to the East, either -1 or +1 */
24    private $east = +1;
25
26    private bool $known = false;
27
28    /**
29     * @param string $name Internal globe name
30     */
31    public function __construct( string $name = self::EARTH ) {
32        global $wgGlobes;
33
34        $this->name = $name;
35
36        $data = $wgGlobes[$name] ?? self::getData()[$name] ?? null;
37        if ( $data !== null ) {
38            $this->radius = $data['radius'] ?? null;
39            $this->minLon = $data['lon'][0] ?? 0;
40            $this->maxLon = $data['lon'][1] ?? $this->minLon + 360;
41            $this->east = $data['east'] ?? +1;
42            $this->known = true;
43        }
44    }
45
46    /**
47     * @return array[]
48     */
49    private static function getData(): array {
50        static $data = [];
51        if ( $data ) {
52            return $data;
53        }
54
55        $earth   = [ 'lon' => [ -180, 180 ], 'east' => +1 ];
56        $east360 = [ 'lon' => [ 0, 360 ], 'east' => +1 ];
57        $west360 = [ 'lon' => [ 0, 360 ], 'east' => -1 ];
58
59        /**
60         * Format:
61         * 'lon' => Array of minimum and maximum longitude, defaults to [ 0, 360 ]
62         * 'east' => If values going to the East are positive or negative, defaults to +1
63         * 'radius' => mean radius in meters (optional)
64         * Coordinate systems mostly taken from http://planetarynames.wr.usgs.gov/TargetCoordinates
65         * Radii taken from Wikipedia. Globes that are too irregular in shape don't have radius set.
66         */
67        $data = [
68            self::EARTH => $earth + [ 'radius' => Math::EARTH_RADIUS ],
69            'mercury'   => $west360 + [ 'radius' => 2439700.0 ],
70            'venus'     => $east360 + [ 'radius' => 6051800.0 ],
71            'moon'      => $earth + [ 'radius' => 1737100.0 ],
72            // Assuming MDIM 2.1
73            'mars'      => $east360 + [ 'radius' => 3389500.0 ],
74            'phobos'    => $west360,
75            'deimos'    => $west360,
76            // 'ceres' => ???,
77            // 'vesta' => ???,
78            'ganymede'  => $west360 + [ 'radius' => 2634100.0 ],
79            'callisto'  => $west360 + [ 'radius' => 2410300.0 ],
80            'io'        => $west360 + [ 'radius' => 1821600.0 ],
81            'europa'    => $west360 + [ 'radius' => 1560800.0 ],
82            'mimas'     => $west360 + [ 'radius' => 198200.0 ],
83            'enceladus' => $west360 + [ 'radius' => 252100.0 ],
84            'tethys'    => $west360 + [ 'radius' => 531100.0 ],
85            'dione'     => $west360 + [ 'radius' => 561400.0 ],
86            'rhea'      => $west360 + [ 'radius' => 763800.0 ],
87            'titan'     => $west360 + [ 'radius' => 2575500.0 ],
88            'hyperion'  => $west360,
89            'iapetus'   => $west360 + [ 'radius' => 734500.0 ],
90            'phoebe'    => $west360,
91            'miranda'   => $east360 + [ 'radius' => 235800.0 ],
92            'ariel'     => $east360 + [ 'radius' => 578900.0 ],
93            'umbriel'   => $east360 + [ 'radius' => 584700.0 ],
94            'titania'   => $east360 + [ 'radius' => 788400.0 ],
95            'oberon'    => $east360 + [ 'radius' => 761400.0 ],
96            'triton'    => $east360 + [ 'radius' => 1353400.0 ],
97            // ???
98            'pluto'     => $east360 + [ 'radius' => 1187000.0 ],
99        ];
100
101        return $data;
102    }
103
104    /**
105     * Globe internal name
106     */
107    public function getName(): string {
108        return $this->name;
109    }
110
111    /**
112     * Returns globe radius or null if it's not known
113     * @return float|null
114     */
115    public function getRadius() {
116        return $this->radius;
117    }
118
119    /**
120     * Returns minimum longitude
121     * @return float
122     */
123    public function getMinLongitude() {
124        return $this->minLon;
125    }
126
127    /**
128     * Returns maximum longitude
129     * @return float
130     */
131    public function getMaxLongitude() {
132        return $this->maxLon;
133    }
134
135    /**
136     * Returns the sign of East
137     * @return int
138     */
139    public function getEastSign() {
140        return $this->east;
141    }
142
143    /**
144     * Returns whether this globe is registered (and hence, we know its properties)
145     */
146    public function isKnown(): bool {
147        return $this->known;
148    }
149
150    /**
151     * Compares this globe to another
152     */
153    public function equalsTo( Globe $other ): bool {
154        return $this->name === $other->name;
155    }
156
157    /**
158     * Checks whether given coordinates are valid
159     * @param int|float|string $lat
160     * @param int|float|string $lon
161     */
162    public function coordinatesAreValid( $lat, $lon ): bool {
163        if ( !is_numeric( $lat ) || !is_numeric( $lon ) ) {
164            return false;
165        }
166        $lat = (float)$lat;
167        $lon = (float)$lon;
168
169        return $lon >= $this->minLon && $lon <= $this->maxLon
170            && abs( $lat ) <= 90;
171    }
172}