Exemplo n.º 1
0
 /**
  * testCalculateDestinationForBearingAndDistanceReturnsExpectedValue
  *
  * @param LatLong $latLong The starting point.
  * @param float $bearing The initial bearing.
  * @param float $distance The distance in metres to travel.
  * @param LatLong $expected The expected destination.
  *
  * @dataProvider getLatLongWithInitialBearingDistanceAndDestination
  */
 public function testCalculateDestinationForBearingAndDistanceReturnsExpectedValue(LatLong $latLong, $bearing, $distance, LatLong $expected)
 {
     $actual = $latLong->calculateDestinationForBearingAndDistance($bearing, $distance);
     $tolerance = 0.3;
     $this->assertEqualsWithinTolerance($expected->getLatitude(), $actual->getLatitude(), $tolerance);
     $this->assertEqualsWithinTolerance($expected->getLongitude(), $actual->getLongitude(), $tolerance);
     $this->assertEquals($latLong->getHeight(), $actual->getHeight());
     // Height remains constant.
     $this->assertEquals($expected->getDatum(), $actual->getDatum());
 }
Exemplo n.º 2
0
 /**
  * Calculate the distance in metres to another LatLong coordinate.
  *
  * This is a relatively expensive calculation to perform.  It treats the Earth as an ellipsoid of the dimensions
  * given for this LatLong's Datum's Ellipsoid so is more accurate than the Spherical law of cosines.
  *
  * @param LatLong $destination The coordinate to measure the distance to.
  *
  * @return float|null The distance in metres, or null if there was a problem.
  *
  * @throws InvalidArgumentException If the datum of this object does not match that of the $destination LatLong.
  */
 public function calculateDistanceVincenty(LatLong $destination)
 {
     if ($destination->getDatum() != $this->datum) {
         throw new InvalidArgumentException('Datums must match to calculate distance.');
     }
     $ellipsoid = $this->datum->getEllipsoid();
     $a = $ellipsoid->getSemiMajorAxisMetres();
     $b = $ellipsoid->getSemiMinorAxisMetres();
     $f = $ellipsoid->getInverseFlattening();
     $longDiffRad = deg2rad($destination->getLongitude() - $this->getLongitude());
     $reducedLat = atan((1 - $f) * tan($this->getLatitudeRadians()));
     $reducedLatDest = atan((1 - $f) * tan($destination->getLatitudeRadians()));
     $sinReducedLat = sin($reducedLat);
     $cosReducedLat = cos($reducedLat);
     $sinReducedLatDest = sin($reducedLatDest);
     $cosReducedLatDest = cos($reducedLatDest);
     $lambda = $longDiffRad;
     $maxIterations = 100;
     do {
         $sinLambda = sin($lambda);
         $cosLambda = cos($lambda);
         $sinSigma = sqrt(pow($cosReducedLatDest * $sinLambda, 2) + pow($cosReducedLat * $sinReducedLatDest - $sinReducedLat * $cosReducedLatDest * $cosLambda, 2));
         // Return 0 if the points are coincident.
         if ($sinSigma === 0.0) {
             return 0.0;
         }
         $cosSigma = $sinReducedLat * $sinReducedLatDest + $cosReducedLat * $cosReducedLatDest * $cosLambda;
         $sigma = atan2($sinSigma, $cosSigma);
         $sinAlpha = $cosReducedLat * $cosReducedLatDest * $sinLambda / $sinSigma;
         $cosSqAlpha = 1 - pow($sinAlpha, 2);
         $cos2SigmaM = 0;
         // At the equator, $cosSqAlpha === 0.
         if ($cosSqAlpha !== 0) {
             $cos2SigmaM = $cosSigma - 2 * $sinReducedLat * $sinReducedLatDest / $cosSqAlpha;
         }
         $c = $f / 16 * $cosSqAlpha * (4 + $f * (4 - 3 * $cosSqAlpha));
         $lambdaP = $lambda;
         $lambda = $longDiffRad + (1 - $c) * $f * $sinAlpha * ($sigma + $c * $sinSigma * ($cos2SigmaM + $c * $cosSigma * (-1 + 2 * $cos2SigmaM * $cos2SigmaM)));
     } while (abs($lambda - $lambdaP) > '1e-12' && --$maxIterations > 0);
     if ($maxIterations === 0) {
         return null;
         // Formula failed to converge.
     }
     $uSq = $cosSqAlpha * ($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)));
     $deltaSigma = $B * $sinSigma * ($cos2SigmaM + $B / 4 * ($cosSigma * (-1 + 2 * $cos2SigmaM * $cos2SigmaM) - $B / 6 * $cos2SigmaM * (-3 + 4 * $sinSigma * $sinSigma) * (-3 + 4 * $cos2SigmaM * $cos2SigmaM)));
     $s = $b * $A * ($sigma - $deltaSigma);
     return $s;
 }