Location\Bearing\BearingEllipsoidal::inverseVincenty PHP Method

inverseVincenty() private method

private inverseVincenty ( Coordinate $point1, Coordinate $point2 )
$point1 Location\Coordinate
$point2 Location\Coordinate
    private function inverseVincenty(Coordinate $point1, Coordinate $point2)
    {
        $φ1 = deg2rad($point1->getLat());
        $φ2 = deg2rad($point2->getLat());
        $λ1 = deg2rad($point1->getLng());
        $λ2 = deg2rad($point2->getLng());
        $a = $point1->getEllipsoid()->getA();
        $b = $point1->getEllipsoid()->getB();
        $f = 1 / $point1->getEllipsoid()->getF();
        $L = $λ2 - $λ1;
        $tanU1 = (1 - $f) * tan($φ1);
        $cosU1 = 1 / sqrt(1 + $tanU1 * $tanU1);
        $sinU1 = $tanU1 * $cosU1;
        $tanU2 = (1 - $f) * tan($φ2);
        $cosU2 = 1 / sqrt(1 + $tanU2 * $tanU2);
        $sinU2 = $tanU2 * $cosU2;
        $λ = $L;
        $iterations = 0;
        do {
            $sinλ = sin($λ);
            $cosλ = cos($λ);
            $sinSqσ = $cosU2 * $sinλ * ($cosU2 * $sinλ) + ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ) * ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ);
            $sinσ = sqrt($sinSqσ);
            if ($sinσ == 0) {
                return 0;
            }
            $cosσ = $sinU1 * $sinU2 + $cosU1 * $cosU2 * $cosλ;
            $σ = atan2($sinσ, $cosσ);
            $sinα = $cosU1 * $cosU2 * $sinλ / $sinσ;
            $cosSqα = 1 - $sinα * $sinα;
            $cos2σM = 0;
            if ($cosSqα !== 0.0) {
                $cos2σM = $cosσ - 2 * $sinU1 * $sinU2 / $cosSqα;
            }
            $C = $f / 16 * $cosSqα * (4 + $f * (4 - 3 * $cosSqα));
            $λp = $λ;
            $λ = $L + (1 - $C) * $f * $sinα * ($σ + $C * $sinσ * ($cos2σM + $C * $cosσ * (-1 + 2 * $cos2σM * $cos2σM)));
        } while (abs($λ - $λp) > 1.0E-12 && ++$iterations < 200);
        if ($iterations >= 200) {
            throw new NotConvergingException('Inverse Vincenty Formula did not converge');
        }
        $uSq = $cosSqα * ($a * $a - $b * $b) / ($b * $b);
        $A = 1 + $uSq / 16384 * (4096 + $uSq * (-768 + $uSq * (320 - 175 * $uSq)));
        $B = $uSq / 1024 * (256 + $uSq * (-128 + $uSq * (74 - 47 * $uSq)));
        $Δσ = $B * $sinσ * ($cos2σM + $B / 4 * ($cosσ * (-1 + 2 * $cos2σM * $cos2σM) - $B / 6 * $cos2σM * (-3 + 4 * $sinσ * $sinσ) * (-3 + 4 * $cos2σM * $cos2σM)));
        $s = $b * $A * ($σ - $Δσ);
        $α1 = atan2($cosU2 * $sinλ, $cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ);
        $α2 = atan2($cosU1 * $sinλ, -$sinU1 * $cosU2 + $cosU1 * $sinU2 * $cosλ);
        $α1 = fmod($α1 + 2 * M_PI, 2 * M_PI);
        $α2 = fmod($α2 + 2 * M_PI, 2 * M_PI);
        $s = round($s, 3);
        return ['distance' => $s, 'bearing_initial' => rad2deg($α1), 'bearing_final' => rad2deg($α2)];
    }