Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Location
- {
- protected $longitude;
- protected $latitude;
- /**
- * Constructs a new location.
- *
- * @param float $lat
- * @param float $lon
- * @throws InvalidArgumentException
- */
- public function __construct($lat, $lon)
- {
- $this->setLatitude($lat);
- $this->setLongitude($lon);
- }
- public function bearingTo(Location $location)
- {
- $result = $this->distanceAndBearing($location);
- return $result['bearing'];
- }
- /**
- * Returns the approximate distance in meters between this location and the given location.
- *
- * @returns float
- */
- public function distanceTo(Location $location)
- {
- $result = $this->distanceAndBearing($location);
- return $result['distance'];
- }
- /**
- * Returns the latitude for this location.
- *
- * @return float
- */
- public function getLatitude()
- {
- return $this->latitude;
- }
- /**
- * Returns the longitude for this location.
- *
- * @return float
- */
- public function getLongitude()
- {
- return $this->longitude;
- }
- /**
- * Sets the latitude for this location.
- *
- * @param float $latitude
- * @throws InvalidArgumentException
- */
- public function setLatitude($latitude)
- {
- if (!is_numeric($latitude))
- {
- throw new InvalidArgumentException("Argument must be numeric.");
- }
- $this->latitude = (float) $latitude;
- }
- /**
- * Sets the longitude for this location.
- *
- * @param float $longitude
- * @throws InvalidArgumentException
- */
- public function setLongitude($longitude)
- {
- if (!is_numeric($longitude))
- {
- throw new InvalidArgumentException("Argument must be numeric.");
- }
- $this->longitude = (float) $longitude;
- }
- private function distanceAndBearing(Location $location)
- {
- // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- // using the "Inverse Formula" (section 4)
- $lat1 = deg2rad($this->getLatitude());
- $lat2 = deg2rad($location->getLatitude());
- $lon1 = deg2rad($this->getLongitude());
- $lon2 = deg2rad($location->getLongitude());
- $major = 6378137.0;
- $minor = 6356752.3142;
- $f = ($major-$minor)/$major;
- $aSqMinusBSqOverBSq = (pow($major, 2) - pow($minor, 2))/($minor*$minor);
- $L = $lon2 - $lon1;
- $U1 = atan((1.0 - $f) * tan($lat1));
- $U2 = atan((1.0 - $f) * tan($lat2));
- $cosU1 = cos($U1);
- $cosU2 = cos($U2);
- $sinU1 = sin($U1);
- $sinU2 = sin($U2);
- $sinU1sinU2 = $sinU1 * $sinU2;
- $cosU1cosU2 = $cosU1 * $cosU2;
- $A = 0.0;
- $cos2SM = 0.0;
- $sinSigma = 0.0;
- $cosSigma = 0.0;
- $deltaSigma = 0.0;
- $sinLambda = 0.0;
- $cosLambda = 0.0;
- $sigma = 0.0;
- $lambda = $L;
- for ($i = 0; $i < 20; $i++)
- {
- $lambdaOrig = $lambda;
- $cosLambda = cos($lambda);
- $sinLambda = sin($lambda);
- $t1 = $cosU1 * $sinLambda;
- $t2 = $cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda;
- $sinSqSigma = pow($t1, 2) + pow($t2, 2);
- $sinSigma = sqrt($sinSqSigma);
- $sinAlpha = ($sinSigma == 0) ? 0.0 : $cosU1cosU2 * $sinLambda / $sinSigma;
- $cosSqAlpha = 1.0 - pow($sinAlpha, 2);
- $uSq = $cosSqAlpha * $aSqMinusBSqOverBSq;
- $A = 1 + ($uSq / 16384.0) * (4096.0 + $uSq * (-768 + $uSq * (320.0 - 175.0 * $uSq)));
- $B = ($uSq / 1024.0) * (256.0 + $uSq * (-128.0 + $uSq * (74.0 - 47.0 * $uSq)));
- $C = ($f / 16.0) * $cosSqAlpha * (4.0 + $f * (4.0 - 3.0 * $cosSqAlpha));
- $cosSigma = $sinU1sinU2 + $cosU1cosU2 * $cosLambda;
- $cos2SM = ($cosSqAlpha == 0) ? 0.0 : $cosSigma - 2.0 * $sinU1sinU2 / $cosSqAlpha;
- $sigma = atan2($sinSigma, $cosSigma);
- $cos2SMSq = pow($cos2SM, 2);
- $deltaSigma = $B * $sinSigma * ($cos2SM + ($B / 4.0) * ($cosSigma * (-1.0 + 2.0 * $cos2SMSq) - ($B / 6.0) * $cos2SM * (-3.0 + 4.0 * pow($sinSigma, 2)) * (-3.0 + 4.0 * $cos2SMSq)));
- $lambda = $L + (1.0 - $C) * $f * $sinAlpha * ($sigma + $C * $sinSigma * ($cos2SM + $C * $cosSigma * (-1.0 + 2.0 * $cos2SM * $cos2SM)));
- $delta = ($lambda - $lambdaOrig) / $lambda;
- if (abs($delta) < 1.0e-12) break;
- }
- $distance = (float) ($minor * $A * ($sigma - $deltaSigma));
- $bearing = (float) rad2deg(atan2($cosU2 * $sinLambda, $cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda));
- return array(
- 'distance' => $distance,
- 'bearing' => $bearing
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement