geotile_sdk
Version:
A tile sdk for Cloud Optimised Geotiff and shapefile
195 lines (157 loc) • 6.04 kB
JavaScript
// tilebelt
const r2d = 180 / Math.PI
function tile2lon (x, z) {
return (x / Math.pow(2, z) * 360 - 180)
}
function tile2lat (y, z) {
var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z)
return (r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))))
}
function tile2BBox (tile) {
var e = tile2lon(tile[0] + 1, tile[2])
var w = tile2lon(tile[0], tile[2])
var s = tile2lat(tile[1] + 1, tile[2])
var n = tile2lat(tile[1], tile[2])
return [w, s, e, n]
}
function pointToTileFraction (lon, lat, z) {
var sin = Math.sin(lat * d2r)
var z2 = Math.pow(2, z)
var x = z2 * (lon / 360 + 0.5)
var y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI)
return [x, y, z]
}
function pointToTile (lon, lat, z) {
var tile = pointToTileFraction(lon, lat, z)
tile[0] = Math.floor(tile[0])
tile[1] = Math.floor(tile[1])
return tile
}
// sshuai
function ul (x, y, z) {
var lonlat = []
var n = Math.pow(2.0, z)
var latRad = Math.atan(Math.sinh(Math.PI * (1.0 - 2.0 * y / n)))
lonlat[1] = latRad * 180.0 / Math.PI
lonlat[0] = x / n * 360.0 - 180.0
return lonlat
};
function bounds (tile) {
var bound = []
var lnglatUL = ul(tile[0], tile[1], tile[2])
bound[0] = lnglatUL[0]
bound[3] = lnglatUL[1]
var lnglatBR = ul(tile[0] + 1, tile[1] + 1, tile[2])
bound[2] = lnglatBR[0]
bound[1] = lnglatBR[1]
return bound
};
export function getUniqueValues (arr) {
function onlyUnique (value, index, self) {
return self.indexOf(value) === index
}
return arr.filter(onlyUnique)
}
export function findUniqueBandShortNamesInString (string) {
var regExpressionTester = /(b)\d+/g
return getUniqueValues(string.match(regExpressionTester))
}
export function latLonTotile (lng, lat, zoom) {
var outTile = []
outTile.x = Math.floor((lng + 180.0) / 360.0 * Math.pow(2.0, zoom))
var lat_ = Math.PI * lat / 180
outTile.y = Math.floor((1.0 - Math.log(Math.tan(lat_) + (1.0 / Math.cos(lat_))) / Math.PI) / 2.0 * Math.pow(2.0, zoom))
outTile.z = zoom
return outTile
};
export function lonlat2WebMercator (lon, lat) {
var xy = []
var x = lon * 20037508.34 / 180
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180)
y = y * 20037508.34 / 180
xy[0] = x
xy[1] = y
return xy
}
export function webMercator2lonlat (x, y) {
var lonlat = []
var lon = x / 20037508.34 * 180
var lat = y / 20037508.34 * 180
lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2)
lonlat[0] = lon
lonlat[1] = lat
return lonlat
}
export function webMercator2tile (x, y, zoom) {
var [lon, lat] = webMercator2lonlat(x, y)
return pointToTile(lon, lat, zoom)
};
export function latLonToUtm (coords, zone, requiresSouthernHemiAdjustment) {
const lat = coords[1]
const lon = coords[0]
if (!(-80 <= lat && lat <= 84)) throw new Error('Outside UTM limits') //eslint-disable-line
const falseEasting = 500e3
const falseNorthing = 10000e3
var λ0 = degreesToRadians(((zone - 1) * 6 - 180 + 3)) // longitude of central meridian
// grid zones are 8° tall; 0°N is offset 10 into latitude bands array
var mgrsLatBands = 'CDEFGHJKLMNPQRSTUVWXX' // X is repeated for 80-84°N
var latBand = mgrsLatBands.charAt(Math.floor(lat / 8 + 10))
// adjust zone & central meridian for Norway
if (zone === 31 && latBand === 'V' && lon >= 3) { zone++; degreesToRadians(λ0 += (6)) }
// adjust zone & central meridian for Svalbard
if (zone === 32 && latBand === 'X' && lon < 9) { zone--; degreesToRadians(λ0 -= (6)) }
if (zone === 32 && latBand === 'X' && lon >= 9) { zone++; degreesToRadians(λ0 += (6)) }
if (zone === 34 && latBand === 'X' && lon < 21) { zone--; degreesToRadians(λ0 -= (6)) }
if (zone === 34 && latBand === 'X' && lon >= 21) { zone++; degreesToRadians(λ0 += (6)) }
if (zone === 36 && latBand === 'X' && lon < 33) { zone--; degreesToRadians(λ0 -= (6)) }
if (zone === 36 && latBand === 'X' && lon >= 33) { zone++; degreesToRadians(λ0 += (6)) }
var φ = degreesToRadians(lat)
var λ = degreesToRadians(lon) - λ0
const a = 6378137
const f = 1 / 298.257223563
// WGS 84: a = 6378137, b = 6356752.314245, f = 1/298.257223563;
var k0 = 0.9996
var e = Math.sqrt(f * (2 - f))
var n = f / (2 - f)
var n2 = n * n
const n3 = n * n2
const n4 = n * n3
const n5 = n * n4
const n6 = n * n5
const cosλ = Math.cos(λ)
const sinλ = Math.sin(λ)
var τ = Math.tan(φ)
var σ = Math.sinh(e * Math.atanh(e * τ / Math.sqrt(1 + τ * τ)))
var τʹ = τ * Math.sqrt(1 + σ * σ) - σ * Math.sqrt(1 + τ * τ)
var ξʹ = Math.atan2(τʹ, cosλ)
var ηʹ = Math.asinh(sinλ / Math.sqrt(τʹ * τʹ + cosλ * cosλ))
var A = a / (1 + n) * (1 + 1 / 4 * n2 + 1 / 64 * n4 + 1 / 256 * n6)
var α = [ null, // note α is one-based array (6th order Krüger expressions)
1 / 2 * n - 2 / 3 * n2 + 5 / 16 * n3 + 41 / 180 * n4 - 127 / 288 * n5 + 7891 / 37800 * n6,
13 / 48 * n2 - 3 / 5 * n3 + 557 / 1440 * n4 + 281 / 630 * n5 - 1983433 / 1935360 * n6,
61 / 240 * n3 - 103 / 140 * n4 + 15061 / 26880 * n5 + 167603 / 181440 * n6,
9561 / 161280 * n4 - 179 / 168 * n5 + 6601661 / 7257600 * n6,
34729 / 80640 * n5 - 3418889 / 1995840 * n6,
212378941 / 319334400 * n6 ]
var ξ = ξʹ
var j = 1
for (j; j <= 6; j++) ξ += α[j] * Math.sin(2 * j * ξʹ) * Math.cosh(2 * j * ηʹ)
var η = ηʹ
for (j = 1; j <= 6; j++) η += α[j] * Math.cos(2 * j * ξʹ) * Math.sinh(2 * j * ηʹ)
var x = k0 * A * η
var y = k0 * A * ξ
x = x + falseEasting
if (requiresSouthernHemiAdjustment && y < 0) y = y + falseNorthing
return [x, y]
};
export function degreesToRadians (degrees) {
return degrees * Math.PI / 180
}
export function scaleValueBetweenRange (value, max, min) {
return (value - min) / (max - min)
}
export function rescaleValueTo256 (oldVal, percentiles) {
if (oldVal < percentiles[0]) return 0
if (oldVal > percentiles[1]) return 255
return (255 - 0) * (oldVal - percentiles[0]) / (percentiles[1] - percentiles[0]) + 0
}