public function toUniversalTransverseMercator()
{
// Convert decimal degrees coordinates to radian.
$phi = deg2rad($this->coordinates->getLatitude());
$lambda = deg2rad($this->coordinates->getLongitude());
// Compute the zone UTM zone.
$zone = (int) (($this->coordinates->getLongitude() + 180.0) / 6) + 1;
// Special zone for South Norway.
// On the southwest coast of Norway, grid zone 32V (9° of longitude in width) is extended further west,
// and grid zone 31V (3° of longitude in width) is correspondingly shrunk to cover only open water.
if ($this->coordinates->getLatitude() >= 56.0 && $this->coordinates->getLatitude() < 64.0 && $this->coordinates->getLongitude() >= 3.0 && $this->coordinates->getLongitude() < 12.0) {
$zone = 32;
}
// Special zone for Svalbard.
// In the region around Svalbard, the four grid zones 31X (9° of longitude in width),
// 33X (12° of longitude in width), 35X (12° of longitude in width), and 37X (9° of longitude in width)
// are extended to cover what would otherwise have been covered by the seven grid zones 31X to 37X.
// The three grid zones 32X, 34X and 36X are not used.
if ($this->coordinates->getLatitude() >= 72.0 && $this->coordinates->getLatitude() < 84.0) {
if ($this->coordinates->getLongitude() >= 0.0 && $this->coordinates->getLongitude() < 9.0) {
$zone = 31;
} elseif ($this->coordinates->getLongitude() >= 9.0 && $this->coordinates->getLongitude() < 21.0) {
$zone = 33;
} elseif ($this->coordinates->getLongitude() >= 21.0 && $this->coordinates->getLongitude() < 33.0) {
$zone = 35;
} elseif ($this->coordinates->getLongitude() >= 33.0 && $this->coordinates->getLongitude() < 42.0) {
$zone = 37;
}
}
// Determines the central meridian for the given UTM zone.
$lambda0 = deg2rad(-183.0 + $zone * 6.0);
$ep2 = (pow($this->coordinates->getEllipsoid()->getA(), 2.0) - pow($this->coordinates->getEllipsoid()->getB(), 2.0)) / pow($this->coordinates->getEllipsoid()->getB(), 2.0);
$nu2 = $ep2 * pow(cos($phi), 2.0);
$nN = pow($this->coordinates->getEllipsoid()->getA(), 2.0) / ($this->coordinates->getEllipsoid()->getB() * sqrt(1 + $nu2));
$t = tan($phi);
$t2 = $t * $t;
$l = $lambda - $lambda0;
$l3coef = 1.0 - $t2 + $nu2;
$l4coef = 5.0 - $t2 + 9 * $nu2 + 4.0 * ($nu2 * $nu2);
$l5coef = 5.0 - 18.0 * $t2 + $t2 * $t2 + 14.0 * $nu2 - 58.0 * $t2 * $nu2;
$l6coef = 61.0 - 58.0 * $t2 + $t2 * $t2 + 270.0 * $nu2 - 330.0 * $t2 * $nu2;
$l7coef = 61.0 - 479.0 * $t2 + 179.0 * ($t2 * $t2) - $t2 * $t2 * $t2;
$l8coef = 1385.0 - 3111.0 * $t2 + 543.0 * ($t2 * $t2) - $t2 * $t2 * $t2;
// Calculate easting.
$easting = $nN * cos($phi) * $l + $nN / 6.0 * pow(cos($phi), 3.0) * $l3coef * pow($l, 3.0) + $nN / 120.0 * pow(cos($phi), 5.0) * $l5coef * pow($l, 5.0) + $nN / 5040.0 * pow(cos($phi), 7.0) * $l7coef * pow($l, 7.0);
// Calculate northing.
$n = ($this->coordinates->getEllipsoid()->getA() - $this->coordinates->getEllipsoid()->getB()) / ($this->coordinates->getEllipsoid()->getA() + $this->coordinates->getEllipsoid()->getB());
$alpha = ($this->coordinates->getEllipsoid()->getA() + $this->coordinates->getEllipsoid()->getB()) / 2.0 * (1.0 + pow($n, 2.0) / 4.0 + pow($n, 4.0) / 64.0);
$beta = -3.0 * $n / 2.0 + 9.0 * pow($n, 3.0) / 16.0 + -3.0 * pow($n, 5.0) / 32.0;
$gamma = 15.0 * pow($n, 2.0) / 16.0 + -15.0 * pow($n, 4.0) / 32.0;
$delta = -35.0 * pow($n, 3.0) / 48.0 + 105.0 * pow($n, 5.0) / 256.0;
$epsilon = 315.0 * pow($n, 4.0) / 512.0;
$northing = $alpha * ($phi + $beta * sin(2.0 * $phi) + $gamma * sin(4.0 * $phi) + $delta * sin(6.0 * $phi) + $epsilon * sin(8.0 * $phi)) + $t / 2.0 * $nN * pow(cos($phi), 2.0) * pow($l, 2.0) + $t / 24.0 * $nN * pow(cos($phi), 4.0) * $l4coef * pow($l, 4.0) + $t / 720.0 * $nN * pow(cos($phi), 6.0) * $l6coef * pow($l, 6.0) + $t / 40320.0 * $nN * pow(cos($phi), 8.0) * $l8coef * pow($l, 8.0);
// Adjust easting and northing for UTM system.
$easting = $easting * AbstractGeotools::UTM_SCALE_FACTOR + 500000.0;
$northing = $northing * AbstractGeotools::UTM_SCALE_FACTOR;
if ($northing < 0.0) {
$northing += 10000000.0;
}
return sprintf('%d%s %d %d', $zone, $this->latitudeBands[(int) (($this->coordinates->getLatitude() + 80) / 8)], $easting, $northing);
}