Created
May 10, 2021 19:25
-
-
Save jhurliman/13e8976f26f7cb53f0981c94769a3f63 to your computer and use it in GitHub Desktop.
Latitude/Longitude conversion to UTM in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type UTM = { | |
easting: number; | |
northing: number; | |
zoneNumber: number; | |
}; | |
export function LatLngToUtm( | |
lat: number, | |
lng: number, | |
zoneNumber?: number, | |
a = 6378137, | |
eccSquared = 0.00669438 | |
): UTM { | |
const lngTemp = lng; | |
const latRad = toRadians(lat); | |
const lngRad = toRadians(lngTemp); | |
zoneNumber ??= LatLngToUtmZone(lat, lng); | |
const lngOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin in middle of zone | |
const lngOriginRad = toRadians(lngOrigin); | |
const eccPrimeSquared = eccSquared / (1 - eccSquared); | |
const N = a / Math.sqrt(1 - eccSquared * Math.sin(latRad) * Math.sin(latRad)); | |
const T = Math.tan(latRad) * Math.tan(latRad); | |
const C = eccPrimeSquared * Math.cos(latRad) * Math.cos(latRad); | |
const A = Math.cos(latRad) * (lngRad - lngOriginRad); | |
const M = | |
a * | |
((1 - | |
eccSquared / 4 - | |
(3 * eccSquared * eccSquared) / 64 - | |
(5 * eccSquared * eccSquared * eccSquared) / 256) * | |
latRad - | |
((3 * eccSquared) / 8 + | |
(3 * eccSquared * eccSquared) / 32 + | |
(45 * eccSquared * eccSquared * eccSquared) / 1024) * | |
Math.sin(2 * latRad) + | |
((15 * eccSquared * eccSquared) / 256 + (45 * eccSquared * eccSquared * eccSquared) / 1024) * | |
Math.sin(4 * latRad) - | |
((35 * eccSquared * eccSquared * eccSquared) / 3072) * Math.sin(6 * latRad)); | |
let easting = | |
0.9996 * | |
N * | |
(A + | |
((1 - T + C) * A * A * A) / 6 + | |
((5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A) / 120) + | |
500000.0; | |
let northing = | |
0.9996 * | |
(M + | |
N * | |
Math.tan(latRad) * | |
((A * A) / 2 + | |
((5 - T + 9 * C + 4 * C * C) * A * A * A * A) / 24 + | |
((61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A) / 720)); | |
if (lat < 0) northing += 10000000.0; | |
return { easting, northing, zoneNumber }; | |
} | |
export function LatLngToUtmZone(lat: number, lng: number): number { | |
if (lng >= 8 && lng <= 13 && lat > 54.5 && lat < 58) { | |
return 32; | |
} else if (lat >= 56.0 && lat < 64.0 && lng >= 3.0 && lng < 12.0) { | |
return 32; | |
} | |
if (lat >= 72.0 && lat < 84.0) { | |
if (lng >= 0.0 && lng < 9.0) { | |
return 31; | |
} else if (lng >= 9.0 && lng < 21.0) { | |
return 33; | |
} else if (lng >= 21.0 && lng < 33.0) { | |
return 35; | |
} else if (lng >= 33.0 && lng < 42.0) { | |
return 37; | |
} | |
} | |
return Math.floor((lng + 180) / 6 + 1); | |
} | |
export function getUtmZoneLetter(latitude: number): string { | |
if (84 >= latitude && latitude >= 72) return "X"; | |
else if (72 > latitude && latitude >= 64) return "W"; | |
else if (64 > latitude && latitude >= 56) return "V"; | |
else if (56 > latitude && latitude >= 48) return "U"; | |
else if (48 > latitude && latitude >= 40) return "T"; | |
else if (40 > latitude && latitude >= 32) return "S"; | |
else if (32 > latitude && latitude >= 24) return "R"; | |
else if (24 > latitude && latitude >= 16) return "Q"; | |
else if (16 > latitude && latitude >= 8) return "P"; | |
else if (8 > latitude && latitude >= 0) return "N"; | |
else if (0 > latitude && latitude >= -8) return "M"; | |
else if (-8 > latitude && latitude >= -16) return "L"; | |
else if (-16 > latitude && latitude >= -24) return "K"; | |
else if (-24 > latitude && latitude >= -32) return "J"; | |
else if (-32 > latitude && latitude >= -40) return "H"; | |
else if (-40 > latitude && latitude >= -48) return "G"; | |
else if (-48 > latitude && latitude >= -56) return "F"; | |
else if (-56 > latitude && latitude >= -64) return "E"; | |
else if (-64 > latitude && latitude >= -72) return "D"; | |
else if (-72 > latitude && latitude >= -80) return "C"; | |
else return "Z"; | |
} | |
function toRadians(deg: number): number { | |
return (deg * Math.PI) / 180; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment