/** * Instantiate a Utm onject from Lat/Long coordinates or a LatLong object. * Returns a new Utm object. */ public static function fromLatLong($latitude, $longitude = null) { // Accept various inputs. if (!isset($longitude)) { // One parameter only supplied. If this is not already a LatLong object, // then convert it into one. if (!is_a($latitude, 'Academe\\Proj4Php\\Mgrs\\LatLongInterface')) { // If some form of array, then let LatLong work out how to interpret it. $latitude = new LatLong($latitude); } $lat = $latitude->getLatitude(); $long = $latitude->getLongitude(); } else { // Coordinates supplied as separate values. $lat = $latitude; $long = $longitude; } // TODO: validate lat and long ranges, assuming they have been set, and throw exception if necessary. // lat: -180 to +180; long: -90 to +90 /* if (...) { // Exception here. throw new \InvalidArgumentException( 'error...' ); ); */ // Convert to radians. $lat_rad = deg2rad($lat); $long_rad = deg2rad($long); // Calculate the zone number. $zone_number = static::calcZoneNumber($lat, $long); // +3 puts origin in middle of zone $long_origin = ($zone_number - 1) * 6 - 180 + 3; $long_origin_rad = deg2rad($long_origin); $ecc_prime_squared = static::$ecc_squared / (1 - static::$ecc_squared); $N = static::$a / sqrt(1 - static::$ecc_squared * pow(sin($lat_rad), 2)); $T = pow(tan($lat_rad), 2); $C = $ecc_prime_squared * pow(cos($lat_rad), 2); $A = cos($lat_rad) * ($long_rad - $long_origin_rad); $M = static::$a * ((1 - static::$ecc_squared / 4 - 3 * pow(static::$ecc_squared, 2) / 64 - 5 * pow(static::$ecc_squared, 3) / 256) * $lat_rad - (3 * static::$ecc_squared / 8 + 3 * pow(static::$ecc_squared, 2) / 32 + 45 * pow(static::$ecc_squared, 3) / 1024) * sin(2 * $lat_rad) + (15 * pow(static::$ecc_squared, 2) / 256 + 45 * pow(static::$ecc_squared, 3) / 1024) * sin(4 * $lat_rad) - 35 * pow(static::$ecc_squared, 3) / 3072 * sin(6 * $lat_rad)); $utm_easting = static::$k0 * $N * ($A + (1 - $T + $C) * pow($A, 3) / 6.0 + (5 - 18 * pow($T, 3) + 72 * $C - 58 * $ecc_prime_squared) * pow($A, 5) / 120.0) + 500000.0; $utm_northing = static::$k0 * ($M + $N * tan($lat_rad) * ($A * $A / 2 + (5 - $T + 9 * $C + 4 * pow($C, 2)) * pow($A, 4) / 24.0 + (61 - 58 * pow($T, 3) + 600 * $C - 330 * $ecc_prime_squared) * pow($A, 6) / 720.0)); if ($lat < 0.0) { // 10,000,000 meter offset for southern hemisphere $utm_northing += 10000000.0; } $northing = round($utm_northing); $easting = round($utm_easting); $zone_number = $zone_number; $zone_letter = static::calcLetterDesignator($lat); // Return a new object instatiation. return new static($northing, $easting, $zone_number, $zone_letter); }
public function testSetYValue() { $latLongObject = new LatLong($this->_xyz); $fluidReturn = $latLongObject->setLongitude($this->_angle); $longitudeValue = $latLongObject->getLongitude(); $this->assertTrue(is_object($longitudeValue)); $this->assertTrue(is_a($longitudeValue, 'Geodetic\\Angle')); $this->assertEquals(12345.6789, $longitudeValue->getValue()); // Test fluid return object $this->assertTrue(is_object($fluidReturn)); // ... of the correct type $this->assertTrue(is_a($fluidReturn, 'Geodetic\\LatLong')); }
/** * Get the midpoint for a great circle route between two Latitude/Longitude objects * * @param LatLong $endPoint The destination point * @return LatLong The midpoint Lat/Long between this Lat/Long and the $endpoint Lat/Long * @throws Exception */ public function getMidpoint(LatLong $endPoint) { $deltaLongitude = $endPoint->getLongitude()->getValue(Angle::RADIANS) - $this->longitude->getValue(Angle::RADIANS); $xModified = cos($endPoint->getLatitude()->getValue(Angle::RADIANS)) * cos($deltaLongitude); $yModified = cos($endPoint->getLatitude()->getValue(Angle::RADIANS)) * sin($deltaLongitude); $midpointLatitude = atan2(sin($this->latitude->getValue(Angle::RADIANS)) + sin($endPoint->getLatitude()->getValue(Angle::RADIANS)), sqrt((cos($this->latitude->getValue(Angle::RADIANS)) + $xModified) * (cos($this->latitude->getValue(Angle::RADIANS)) + $xModified) + $yModified * $yModified)); $midpointLongitude = $this->longitude->getValue(Angle::RADIANS) + atan2($yModified, cos($this->latitude->getValue(Angle::RADIANS)) + $xModified); return new LatLong(new LatLong\CoordinateValues(self::cleanLatitude($midpointLatitude), self::cleanLongitude($midpointLongitude), Angle::RADIANS)); }
/** * Identify whether a specified Latitude/Longitude falls within the bounds of this region * * @param LatLong The Latitude/Longitude object that we wish to test * @return boolean */ public function isInRegion(LatLong $position) { $latitude = $position->getLatitude()->getValue(); $longitude = $position->getLongitude()->getValue(); $perimeterNodeCount = count($this->nodePoints); $jIndex = $perimeterNodeCount - 1; $oddNodes = false; for ($iIndex = 0; $iIndex < $perimeterNodeCount; ++$iIndex) { $iLatitude = $this->nodePoints[$iIndex]->getLatitude()->getValue(); $jLatitude = $this->nodePoints[$jIndex]->getLatitude()->getValue(); if ($iLatitude < $latitude && $jLatitude >= $latitude || $jLatitude < $latitude && $iLatitude >= $latitude) { $iLongitude = $this->nodePoints[$iIndex]->getLongitude()->getValue(); $jLongitude = $this->nodePoints[$jIndex]->getLongitude()->getValue(); if ($iLongitude + ($latitude - $iLatitude) / ($jLatitude - $iLatitude) * ($jLongitude - $iLongitude) < $longitude) { $oddNodes = !$oddNodes; } } $jIndex = $iIndex; } return $oddNodes; }