Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
42.11% |
24 / 57 |
|
90.00% |
9 / 10 |
CRAP | |
0.00% |
0 / 1 |
| Globe | |
42.11% |
24 / 57 |
|
90.00% |
9 / 10 |
73.08 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
| getData | |
8.33% |
3 / 36 |
|
0.00% |
0 / 1 |
5.08 | |||
| getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getRadius | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getMinLongitude | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getMaxLongitude | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getEastSign | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isKnown | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| equalsTo | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| coordinatesAreValid | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace GeoData; |
| 4 | |
| 5 | /** |
| 6 | * Immutable representation of a celestial body |
| 7 | */ |
| 8 | class 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 | } |