| Total Complexity | 50 |
| Total Lines | 432 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 1 | Features | 0 |
Complex classes like Geodesic often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Geodesic, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 40 | class Geodesic |
||
| 41 | { |
||
| 42 | private float $a; |
||
| 43 | private float $b; |
||
| 44 | private float $f; |
||
| 45 | private float $f1; |
||
| 46 | private float $e2; |
||
| 47 | private float $ep2; |
||
| 48 | private float $n; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @var float[] |
||
| 52 | */ |
||
| 53 | private array $a3Coefficients; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * @var float[] |
||
| 57 | */ |
||
| 58 | private array $c3Coefficients; |
||
| 59 | |||
| 60 | public function __construct(Ellipsoid $ellipsoid) |
||
| 61 | { |
||
| 62 | $this->a = $ellipsoid->getSemiMajorAxis()->asMetres()->getValue(); |
||
| 63 | $this->b = $ellipsoid->getSemiMinorAxis()->asMetres()->getValue(); |
||
| 64 | $this->f = $ellipsoid->getFlattening(); |
||
| 65 | $this->f1 = 1 - $this->f; |
||
| 66 | $this->e2 = $ellipsoid->getEccentricitySquared(); |
||
| 67 | $this->ep2 = $this->e2 / $this->f1 ** 2; |
||
| 68 | $this->n = $this->f / (2 - $this->f); |
||
| 69 | $this->a3Coefficients = $this->a3Coefficients(); |
||
| 70 | $this->c3Coefficients = $this->c3Coefficients(); |
||
| 71 | } |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @return float[] |
||
| 75 | */ |
||
| 76 | private function a3Coefficients(): array |
||
| 77 | { |
||
| 78 | $A3x = []; |
||
| 79 | $coeff = [ |
||
| 80 | -3, 128, |
||
| 81 | -2, -3, 64, |
||
| 82 | -1, -3, -1, 16, |
||
| 83 | 3, -1, -2, 8, |
||
| 84 | 1, -1, 2, |
||
| 85 | 1, 1, |
||
| 86 | ]; |
||
| 87 | $o = 0; |
||
| 88 | $k = 0; |
||
| 89 | foreach (range(5, 0, -1) as $j) { |
||
| 90 | $m = min(5 - $j, $j); |
||
| 91 | $A3x[$k] = polyVal($m, $coeff, $o, $this->n) / $coeff[$o + $m + 1]; |
||
| 92 | ++$k; |
||
| 93 | $o += $m + 2; |
||
| 94 | } |
||
| 95 | |||
| 96 | return $A3x; |
||
| 97 | } |
||
| 98 | |||
| 99 | /** |
||
| 100 | * @return float[] |
||
| 101 | */ |
||
| 102 | private function c3Coefficients(): array |
||
| 103 | { |
||
| 104 | $C3x = []; |
||
| 105 | |||
| 106 | $coeff = [ |
||
| 107 | 3, 128, |
||
| 108 | 2, 5, 128, |
||
| 109 | -1, 3, 3, 64, |
||
| 110 | -1, 0, 1, 8, |
||
| 111 | -1, 1, 4, |
||
| 112 | 5, 256, |
||
| 113 | 1, 3, 128, |
||
| 114 | -3, -2, 3, 64, |
||
| 115 | 1, -3, 2, 32, |
||
| 116 | 7, 512, |
||
| 117 | -10, 9, 384, |
||
| 118 | 5, -9, 5, 192, |
||
| 119 | 7, 512, |
||
| 120 | -14, 7, 512, |
||
| 121 | 21, 2560, |
||
| 122 | ]; |
||
| 123 | $o = 0; |
||
| 124 | $k = 0; |
||
| 125 | foreach (range(1, 5) as $l) { |
||
| 126 | foreach (range(5, $l, -1) as $j) { |
||
| 127 | $m = min(5 - $j, $j); |
||
| 128 | $C3x[$k] = polyVal($m, $coeff, $o, $this->n) / $coeff[$o + $m + 1]; // @phpstan-ignore binaryOp.invalid |
||
| 129 | ++$k; |
||
| 130 | $o += $m + 2; |
||
| 131 | } |
||
| 132 | } |
||
| 133 | |||
| 134 | return $C3x; |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * @return float[] |
||
| 139 | */ |
||
| 140 | private function c3(float $eps): array |
||
| 141 | { |
||
| 142 | $c = []; |
||
| 143 | $mult = 1; |
||
| 144 | $o = 0; |
||
| 145 | foreach (range(1, 5) as $l) { |
||
| 146 | $m = 5 - $l; |
||
| 147 | $mult *= $eps; |
||
| 148 | $c[$l] = $mult * polyVal($m, $this->c3Coefficients, $o, $eps); |
||
| 149 | $o += $m + 1; |
||
| 150 | } |
||
| 151 | |||
| 152 | return $c; |
||
| 153 | } |
||
| 154 | |||
| 155 | /** |
||
| 156 | * @return float[] |
||
| 157 | */ |
||
| 158 | private function lengths( |
||
| 182 | } |
||
| 183 | |||
| 184 | /** |
||
| 185 | * @return float[] |
||
| 186 | */ |
||
| 187 | private function inverseStart( |
||
| 188 | float $sbet1, |
||
| 189 | float $cbet1, |
||
| 190 | float $sbet2, |
||
| 191 | float $cbet2, |
||
| 192 | float $lam12, |
||
| 193 | float $slam12, |
||
| 194 | float $clam12, |
||
| 195 | ): array { |
||
| 196 | $sig12 = -1; |
||
| 197 | $dnm = 1; |
||
| 198 | $sbet12 = $sbet2 * $cbet1 - $cbet2 * $sbet1; |
||
| 199 | $cbet12 = $cbet2 * $cbet1 + $sbet2 * $sbet1; |
||
| 200 | $sbet12a = $sbet2 * $cbet1; |
||
| 201 | $sbet12a += $cbet2 * $sbet1; |
||
| 202 | |||
| 203 | $shortline = ($cbet12 >= 0 && $sbet12 < 0.5 && $cbet2 * $lam12 < 0.5); |
||
| 204 | if ($shortline) { |
||
| 205 | $sbetm2 = ($sbet1 + $sbet2) ** 2; |
||
| 206 | $sbetm2 /= $sbetm2 + ($cbet1 + $cbet2) ** 2; |
||
| 207 | $dnm = sqrt(1 + $this->ep2 * $sbetm2); |
||
| 208 | $omg12 = $lam12 / ($this->f1 * $dnm); |
||
| 209 | $somg12 = sin($omg12); |
||
| 210 | $comg12 = cos($omg12); |
||
| 211 | } else { |
||
| 212 | $somg12 = $slam12; |
||
| 213 | $comg12 = $clam12; |
||
| 214 | } |
||
| 215 | $salp1 = $cbet2 * $somg12; |
||
| 216 | $calp1 = $comg12 >= 0 ? |
||
| 217 | $sbet12 + $cbet2 * $sbet1 * $somg12 ** 2 / (1 + $comg12) : $sbet12a - $cbet2 * $sbet1 * $somg12 ** 2 / (1 - $comg12); |
||
| 218 | |||
| 219 | $ssig12 = hypot($salp1, $calp1); |
||
| 220 | $csig12 = $sbet1 * $sbet2 + $cbet1 * $cbet2 * $comg12; |
||
| 221 | |||
| 222 | if ($shortline && $ssig12 < PHP_FLOAT_EPSILON) { |
||
| 223 | $sig12 = atan2($ssig12, $csig12); |
||
| 224 | } elseif (!(abs($this->n) >= 0.1 || $csig12 >= 0 || $ssig12 >= 6 * abs($this->n) * M_PI * $cbet1 ** 2)) { |
||
| 225 | $lam12x = atan2(-$slam12, -$clam12); |
||
| 226 | $k2 = $sbet1 ** 2 * $this->ep2; |
||
| 227 | $eps = $k2 / (2 * (1 + sqrt(1 + $k2)) + $k2); |
||
| 228 | $lamscale = $this->f * $cbet1 * polyVal(5, $this->a3Coefficients, 0, $eps) * M_PI; |
||
| 229 | $betscale = $lamscale * $cbet1; |
||
| 230 | $x = $lam12x / $lamscale; |
||
| 231 | $y = $sbet12a / $betscale; |
||
| 232 | |||
| 233 | if ($y > -PHP_FLOAT_EPSILON && $x > -1 - PHP_FLOAT_EPSILON) { |
||
| 234 | $salp1 = min(1.0, -$x); |
||
| 235 | $calp1 = -sqrt(1 - $salp1 ** 2); |
||
| 236 | } else { |
||
| 237 | $k = astroid($x, $y); |
||
| 238 | $omg12a = $lamscale * ($this->f >= 0 ? -$x * $k / (1 + $k) : -$y * (1 + $k) / $k); |
||
| 239 | $somg12 = sin($omg12a); |
||
| 240 | $comg12 = -cos($omg12a); |
||
| 241 | $salp1 = $cbet2 * $somg12; |
||
| 242 | $calp1 = $sbet12a - $cbet2 * $sbet1 * $somg12 ** 2 / (1 - $comg12); |
||
| 243 | } |
||
| 244 | } |
||
| 245 | if (!($salp1 <= 0)) { |
||
| 246 | [$salp1, $calp1] = normalise($salp1, $calp1); |
||
| 247 | } else { |
||
| 248 | $salp1 = 1; |
||
| 249 | $calp1 = 0; |
||
| 250 | } |
||
| 251 | |||
| 252 | return [$sig12, $salp1, $calp1, $dnm]; |
||
| 253 | } |
||
| 254 | |||
| 255 | /** |
||
| 256 | * @return float[] |
||
| 257 | */ |
||
| 258 | private function lambda( |
||
| 259 | float $sbet1, |
||
| 260 | float $cbet1, |
||
| 261 | float $dn1, |
||
| 262 | float $sbet2, |
||
| 263 | float $cbet2, |
||
| 264 | float $dn2, |
||
| 265 | float $salp1, |
||
| 266 | float $calp1, |
||
| 267 | float $slam120, |
||
| 268 | float $clam120, |
||
| 269 | ): array { |
||
| 270 | if ($sbet1 == 0 && $calp1 == 0) { |
||
| 271 | $calp1 = -PHP_FLOAT_MIN; |
||
| 272 | } |
||
| 273 | |||
| 274 | $salp0 = $salp1 * $cbet1; |
||
| 275 | $calp0 = hypot($calp1, $salp1 * $sbet1); |
||
| 276 | |||
| 277 | $ssig1 = $sbet1; |
||
| 278 | $somg1 = $salp0 * $sbet1; |
||
| 279 | $csig1 = $comg1 = $calp1 * $cbet1; |
||
| 280 | [$ssig1, $csig1] = normalise($ssig1, $csig1); |
||
| 281 | |||
| 282 | $calp2 = $cbet2 !== $cbet1 || abs($sbet2) !== -$sbet1 ? |
||
| 283 | sqrt(($calp1 * $cbet1) ** 2 + ($cbet1 < -$sbet1 ? |
||
| 284 | ($cbet2 - $cbet1) * ($cbet1 + $cbet2) : |
||
| 285 | ($sbet1 - $sbet2) * ($sbet1 + $sbet2))) / |
||
| 286 | $cbet2 : abs($calp1); |
||
| 287 | |||
| 288 | $ssig2 = $sbet2; |
||
| 289 | $somg2 = $salp0 * $sbet2; |
||
| 290 | $csig2 = $comg2 = $calp2 * $cbet2; |
||
| 291 | [$ssig2, $csig2] = normalise($ssig2, $csig2); |
||
| 292 | |||
| 293 | $sig12 = atan2( |
||
| 294 | max(0.0, $csig1 * $ssig2 - $ssig1 * $csig2), |
||
| 295 | $csig1 * $csig2 + $ssig1 * $ssig2 |
||
| 296 | ); |
||
| 297 | |||
| 298 | $somg12 = max(0.0, $comg1 * $somg2 - $somg1 * $comg2); |
||
| 299 | $comg12 = $comg1 * $comg2 + $somg1 * $somg2; |
||
| 300 | $eta = atan2( |
||
| 301 | $somg12 * $clam120 - $comg12 * $slam120, |
||
| 302 | $comg12 * $clam120 + $somg12 * $slam120 |
||
| 303 | ); |
||
| 304 | |||
| 305 | $k2 = $calp0 ** 2 * $this->ep2; |
||
| 306 | $eps = $k2 / (2 * (1 + sqrt(1 + $k2)) + $k2); |
||
| 307 | $C3a = $this->c3($eps); |
||
| 308 | $B312 = (sinCosSeries($ssig2, $csig2, $C3a) - sinCosSeries($ssig1, $csig1, $C3a)); |
||
| 309 | $domg12 = -$this->f * polyVal(5, $this->a3Coefficients, 0, $eps) * $salp0 * ($sig12 + $B312); |
||
| 310 | $lam12 = $eta + $domg12; |
||
| 311 | |||
| 312 | if ($calp2 == 0) { |
||
| 313 | $dlam12 = -2 * $this->f1 * $dn1 / $sbet1; |
||
| 314 | } else { |
||
| 315 | [, $dlam12] = $this->lengths( |
||
| 316 | $eps, |
||
| 317 | $sig12, |
||
| 318 | $ssig1, |
||
| 319 | $csig1, |
||
| 320 | $dn1, |
||
| 321 | $ssig2, |
||
| 322 | $csig2, |
||
| 323 | $dn2, |
||
| 324 | ); |
||
| 325 | $dlam12 *= $this->f1 / ($calp2 * $cbet2); |
||
| 326 | } |
||
| 327 | |||
| 328 | return [$lam12, $sig12, $ssig1, $csig1, $ssig2, $csig2, $eps, $dlam12]; |
||
| 329 | } |
||
| 330 | |||
| 331 | public function distance(GeographicValue $from, GeographicValue $to): Length |
||
| 472 | } |
||
| 473 | } |
||
| 474 | |||
| 475 | function copySign(float $x, float $y): float |
||
| 476 | { |
||
| 477 | if ($y >= 0) { |
||
| 478 | return abs($x); |
||
| 673 |