UTMtoLL static method Null safety
- UTM utm
Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience class where the Zone can be specified as a single string eg."60N" which is then broken down into the ZoneNumber and ZoneLetter.
@private @param {object} utm An object literal with northing, easting, zoneNumber and zoneLetter properties. If an optional accuracy property is provided (in meters), a bounding box will be returned instead of latitude and longitude. @return {object} An object literal containing either lat and lon values (if no accuracy was provided), or top, right, bottom and left values for the bounding box calculated according to the provided accuracy. Returns null if the conversion failed.
Implementation
static dynamic UTMtoLL(UTM utm) {
var UTMNorthing = utm.northing;
var UTMEasting = utm.easting;
var zoneLetter = utm.zoneLetter;
var zoneNumber = utm.zoneNumber;
// check the ZoneNummber is valid
if (zoneNumber < 0 || zoneNumber > 60) {
return null;
}
const k0 = 0.9996;
const a = 6378137; //ellip.radius;
const eccSquared = 0.00669438; //ellip.eccsq;
var e1 = (1 - math.sqrt(1 - eccSquared)) / (1 + math.sqrt(1 - eccSquared));
// remove 500,000 meter offset for longitude
var x = UTMEasting - 500000;
var y = UTMNorthing;
// We must know somehow if we are in the Northern or Southern
// hemisphere, this is the only time we use the letter So even
// if the Zone letter isn't exactly correct it should indicate
// the hemisphere correctly
if (ALPHABET.indexOf(zoneLetter.toLowerCase()) <
ALPHABET.indexOf('N'.toLowerCase())) {
y -= 10000000; // remove 10,000,000 meter offset used
// for southern hemisphere
}
// There are 60 zones with zone 1 being at West -180 to -174
var LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
// in middle of zone
var eccPrimeSquared = (eccSquared) / (1 - eccSquared);
var M = y / k0;
var mu = M /
(a *
(1 -
eccSquared / 4 -
3 * eccSquared * eccSquared / 64 -
5 * eccSquared * eccSquared * eccSquared / 256));
var phi1Rad = mu +
(3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * math.sin(2 * mu) +
(21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * math.sin(4 * mu) +
(151 * e1 * e1 * e1 / 96) * math.sin(6 * mu);
var N1 =
a / math.sqrt(1 - eccSquared * math.sin(phi1Rad) * math.sin(phi1Rad));
var T1 = math.tan(phi1Rad) * math.tan(phi1Rad);
var C1 = eccPrimeSquared * math.cos(phi1Rad) * math.cos(phi1Rad);
var R1 = a *
(1 - eccSquared) /
math.pow(1 - eccSquared * math.sin(phi1Rad) * math.sin(phi1Rad), 1.5);
var D = x / (N1 * k0);
var lat = phi1Rad -
(N1 * math.tan(phi1Rad) / R1) *
(D * D / 2 -
(5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) *
D *
D *
D *
D /
24 +
(61 +
90 * T1 +
298 * C1 +
45 * T1 * T1 -
252 * eccPrimeSquared -
3 * C1 * C1) *
D *
D *
D *
D *
D *
D /
720);
lat = radToDeg(lat);
var lon = (D -
(1 + 2 * T1 + C1) * D * D * D / 6 +
(5 -
2 * C1 +
28 * T1 -
3 * C1 * C1 +
8 * eccPrimeSquared +
24 * T1 * T1) *
D *
D *
D *
D *
D /
120) /
math.cos(phi1Rad);
lon = LongOrigin + radToDeg(lon);
if (utm.accuracy != null) {
var topRight = UTMtoLL(
UTM(
easting: utm.easting + utm.accuracy!,
northing: utm.northing + utm.accuracy!,
zoneLetter: utm.zoneLetter,
zoneNumber: utm.zoneNumber,
accuracy: null,
),
);
return BBox(
top: topRight.lat, right: topRight.lon, bottom: lat, left: lon);
} else {
return LonLat(lat: lat, lon: lon);
}
}