/** * Get the distance between two Latitude/Longitude objects using the Vincenty formula * * The Vincenty Formula calculates the distance to your destination point based on the specified ellipsoid * * @param LatLong $endPoint The destination point * @param ReferenceEllipsoid $ellipsoid * @return Distance The great circle distance between this Lat/Long and the $endpoint Lat/Long * @throws Exception */ public function getDistanceVincenty(LatLong $endPoint, ReferenceEllipsoid $ellipsoid = null) { if (is_null($ellipsoid)) { $ellipsoid = new ReferenceEllipsoid(ReferenceEllipsoid::WGS_84); } $semiMinor = $ellipsoid->getSemiMinorAxis(); $flattening = $ellipsoid->getFlattening(); $lDifference = $this->longitude->getValue(Angle::RADIANS) - $endPoint->getLongitude()->getValue(Angle::RADIANS); $U1Value = atan((1 - $flattening) * tan($endPoint->getLatitude()->getValue(Angle::RADIANS))); $U2Value = atan((1 - $flattening) * tan($this->latitude->getValue(Angle::RADIANS))); $sinU1 = sin($U1Value); $cosU1 = cos($U1Value); $sinU2 = sin($U2Value); $cosU2 = cos($U2Value); $lambda = $lDifference; $lambdaP = 2 * M_PI; $iterLimit = 20; while (abs($lambda - $lambdaP) > 1.0E-12 && $iterLimit > 0) { $sinLambda = sin($lambda); $cosLambda = cos($lambda); $sinSigma = sqrt($cosU2 * $sinLambda * ($cosU2 * $sinLambda) + ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda) * ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda)); if ($sinSigma == 0.0) { // co-incident points return new Distance(); } $cosSigma = $sinU1 * $sinU2 + $cosU1 * $cosU2 * $cosLambda; $sigma = atan2($sinSigma, $cosSigma); $alpha = asin($cosU1 * $cosU2 * $sinLambda / $sinSigma); $cosSqAlpha = cos($alpha) * cos($alpha); $cos2SigmaM = $cosSigma - 2 * $sinU1 * $sinU2 / $cosSqAlpha; $cValue = $flattening / 16 * $cosSqAlpha * (4 + $flattening * (4 - 3 * $cosSqAlpha)); $lambdaP = $lambda; $lambda = $lDifference + (1 - $cValue) * $flattening * sin($alpha) * ($sigma + $cValue * $sinSigma * ($cos2SigmaM + $cValue * $cosSigma * (-1 + 2 * $cos2SigmaM * $cos2SigmaM))); } $uSq = $cosSqAlpha * $ellipsoid->getSecondEccentricitySquared(); $aValue = 1 + $uSq / 16384 * (4096 + $uSq * (-768 + $uSq * (320 - 175 * $uSq))); $bValue = $uSq / 1024 * (256 + $uSq * (-128 + $uSq * (74 - 47 * $uSq))); $deltaSigma = $bValue * $sinSigma * ($cos2SigmaM + $bValue / 4 * ($cosSigma * (-1 + 2 * $cos2SigmaM * $cos2SigmaM) - $bValue / 6 * $cos2SigmaM * (-3 + 4 * $sinSigma * $sinSigma) * (-3 + 4 * $cos2SigmaM * $cos2SigmaM))); return new Distance($semiMinor * $aValue * ($sigma - $deltaSigma)); }
public function testGetEllipsoidNames() { $referenceEllipsoidNames = ReferenceEllipsoid::getEllipsoidNames(); $this->assertGreaterThan(0, count($referenceEllipsoidNames)); $this->assertTrue(in_array('Airy (1830)', $referenceEllipsoidNames)); }
/** * Get the Area of this region * * The algorithm used here is derived from the algorithm used by the GRASS GIS package * * @param ReferenceEllipsoid|null $ellipsoid Reference Ellipsoid to use for this calculation * If null, then the WGS 1984 Ellipsoid will be used * @return Area The area of this region */ public function getArea(ReferenceEllipsoid $ellipsoid = null) { $pointCount = count($this->nodePoints); if ($pointCount == 0) { return new Area(); } elseif (is_null($ellipsoid)) { $ellipsoid = new ReferenceEllipsoid(ReferenceEllipsoid::WGS_1984); } $semiMajorAxis = $ellipsoid->getSemiMajorAxis(); $eccentricitySquared = $ellipsoid->getFirstEccentricitySquared(); $eccentricity4 = $eccentricitySquared * $eccentricitySquared; $eccentricity6 = $eccentricity4 * $eccentricitySquared; $AE = $semiMajorAxis * $semiMajorAxis * (1 - $eccentricitySquared); $this->QA = 2.0 / 3.0 * $eccentricitySquared; $this->QB = 3.0 / 5.0 * $eccentricity4; $this->QC = 4.0 / 7.0 * $eccentricity6; $this->QbarA = -1.0 - 2.0 / 3.0 * $eccentricitySquared - 3.0 / 5.0 * $eccentricity4 - 4.0 / 7.0 * $eccentricity6; $this->QbarB = 2.0 / 9.0 * $eccentricitySquared + 2.0 / 5.0 * $eccentricity4 + 4.0 / 7.0 * $eccentricity6; $this->QbarC = -(3.0 / 25.0) * $eccentricity4 - 12.0 / 35.0 * $eccentricity6; $this->QbarD = 4.0 / 49.0 * $eccentricity6; $Qp = $this->_Q(M_PI_2); $pointCount--; $longitude2 = $this->nodePoints[$pointCount]->getLongitude()->getValue(Angle::RADIANS); $latitude2 = $this->nodePoints[$pointCount]->getLatitude()->getValue(Angle::RADIANS); $Qbar2 = $this->_Qbar($latitude2); $area = 0.0; $n = 0; while ($n++ < $pointCount) { $longitude1 = $longitude2; $latitude1 = $latitude2; $Qbar1 = $Qbar2; $longitude2 = $this->nodePoints[$n]->getLongitude()->getValue(Angle::RADIANS); $latitude2 = $this->nodePoints[$n]->getLatitude()->getValue(Angle::RADIANS); $Qbar2 = $this->_Qbar($latitude2); self::datelineAdjust($longitude1, $longitude2); $deltaLongitude = $longitude2 - $longitude1; $area += $deltaLongitude * ($Qp - $this->_Q($latitude2)); if (($deltaLatitude = $latitude2 - $latitude1) != 0.0) { $area += $deltaLongitude * $this->_Q($latitude2) - $deltaLongitude / $deltaLatitude * ($Qbar2 - $Qbar1); } } $area = self::polarAdjust($area, $AE, $Qp); return new Area($area); }