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