62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
export interface LonLatPoint {
|
|
lon: number
|
|
lat: number
|
|
}
|
|
|
|
export interface WebMercatorPoint {
|
|
x: number
|
|
y: number
|
|
}
|
|
|
|
export interface WorldTilePoint {
|
|
x: number
|
|
y: number
|
|
}
|
|
|
|
const MAX_LATITUDE = 85.05112878
|
|
const EARTH_RADIUS = 6378137
|
|
|
|
function clampLatitude(lat: number): number {
|
|
return Math.max(-MAX_LATITUDE, Math.min(MAX_LATITUDE, lat))
|
|
}
|
|
|
|
export function lonLatToWebMercator(point: LonLatPoint): WebMercatorPoint {
|
|
const latitude = clampLatitude(point.lat)
|
|
const lonRad = point.lon * Math.PI / 180
|
|
const latRad = latitude * Math.PI / 180
|
|
|
|
return {
|
|
x: EARTH_RADIUS * lonRad,
|
|
y: EARTH_RADIUS * Math.log(Math.tan(Math.PI / 4 + latRad / 2)),
|
|
}
|
|
}
|
|
|
|
export function webMercatorToLonLat(point: WebMercatorPoint): LonLatPoint {
|
|
return {
|
|
lon: point.x / EARTH_RADIUS * 180 / Math.PI,
|
|
lat: (2 * Math.atan(Math.exp(point.y / EARTH_RADIUS)) - Math.PI / 2) * 180 / Math.PI,
|
|
}
|
|
}
|
|
|
|
export function lonLatToWorldTile(point: LonLatPoint, zoom: number): WorldTilePoint {
|
|
const latitude = clampLatitude(point.lat)
|
|
const scale = Math.pow(2, zoom)
|
|
const latRad = latitude * Math.PI / 180
|
|
|
|
return {
|
|
x: (point.lon + 180) / 360 * scale,
|
|
y: (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * scale,
|
|
}
|
|
}
|
|
|
|
export function worldTileToLonLat(point: WorldTilePoint, zoom: number): LonLatPoint {
|
|
const scale = Math.pow(2, zoom)
|
|
const lon = point.x / scale * 360 - 180
|
|
const latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * point.y / scale)))
|
|
|
|
return {
|
|
lon,
|
|
lat: latRad * 180 / Math.PI,
|
|
}
|
|
}
|