projection.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. export interface LonLatPoint {
  2. lon: number
  3. lat: number
  4. }
  5. export interface WebMercatorPoint {
  6. x: number
  7. y: number
  8. }
  9. export interface WorldTilePoint {
  10. x: number
  11. y: number
  12. }
  13. const MAX_LATITUDE = 85.05112878
  14. const EARTH_RADIUS = 6378137
  15. function clampLatitude(lat: number): number {
  16. return Math.max(-MAX_LATITUDE, Math.min(MAX_LATITUDE, lat))
  17. }
  18. export function lonLatToWebMercator(point: LonLatPoint): WebMercatorPoint {
  19. const latitude = clampLatitude(point.lat)
  20. const lonRad = point.lon * Math.PI / 180
  21. const latRad = latitude * Math.PI / 180
  22. return {
  23. x: EARTH_RADIUS * lonRad,
  24. y: EARTH_RADIUS * Math.log(Math.tan(Math.PI / 4 + latRad / 2)),
  25. }
  26. }
  27. export function webMercatorToLonLat(point: WebMercatorPoint): LonLatPoint {
  28. return {
  29. lon: point.x / EARTH_RADIUS * 180 / Math.PI,
  30. lat: (2 * Math.atan(Math.exp(point.y / EARTH_RADIUS)) - Math.PI / 2) * 180 / Math.PI,
  31. }
  32. }
  33. export function lonLatToWorldTile(point: LonLatPoint, zoom: number): WorldTilePoint {
  34. const latitude = clampLatitude(point.lat)
  35. const scale = Math.pow(2, zoom)
  36. const latRad = latitude * Math.PI / 180
  37. return {
  38. x: (point.lon + 180) / 360 * scale,
  39. y: (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * scale,
  40. }
  41. }
  42. export function worldTileToLonLat(point: WorldTilePoint, zoom: number): LonLatPoint {
  43. const scale = Math.pow(2, zoom)
  44. const lon = point.x / scale * 360 - 180
  45. const latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * point.y / scale)))
  46. return {
  47. lon,
  48. lat: latRad * 180 / Math.PI,
  49. }
  50. }