maps

Web Mercator Projection

Coordinates of places around the world are given in latitude and longitude. They are expressed in degrees and look like this: (50.06°,19.93°)(50.06 \degree, 19.93 \degree). This post is a short explanation of them and how to convert them to meters.

Worth knowing

A reference ellipsoid approximates the shape of the Earth – almost a sphere but slightly flattened. A geodetic datum provides the reference framework for coordinates such as longitude (λ\lambda) and latitude (ϕ\phi).

The Mercator projection is cylindrical and conformal, meaning it preserves local angles. The poles project infinitely far away. The usual Web Mercator tile scheme clips latitude to ±85.05112878°\pm85.05112878\degree to make the projected world a square.

On web, starting with Google Maps, another very similar projection, called Web Mercator, is used. What makes it different from the standard one is that while it uses the same coordinates from the WGS84 standard, it projects them as if they were defined on a sphere. It might sound like a bad idea to completely abandon the notion of Earth being not a perfect sphere. Turns out, it doesn’t really matter compared to the distortion created by the Mercator itself. And it makes the math much easier.

Web Mercator is used by, just to name a few, Google Maps, Bing Maps, Apple Maps, OpenStreetMap. Pretty much the whole web map industry. So unless for a special use case, there’s little reason to go back to the standard one.

The formulas

Now the most interesting part – the formulas for translating degrees to projected meters. Keep in mind that these are not ground distances. The local scale grows as we move away from the Equator.

Variables

aa – semi-major axis of the ellipsoid (radius at the Equator)
ee – eccentricity of the ellipsoid (shape of the ellipsoid)

ϕ\phi – latitude (in radians)

λ\lambda – longitude (in radians)

Mercator

x=aλy=atanh⁡−1(sin⁡ϕ)−aetanh⁡−1(esin⁡ϕ)x = a \lambda \\ y = a \tanh^{-1}(\sin\phi) - ae \tanh^{-1}(e\sin\phi)

Web Mercator

x=aλy=atanh⁡−1(sin⁡ϕ)x = a \lambda \\ y = a \tanh^{-1}(\sin\phi)

The TypeScript code for doing the conversion using Web Mercator goes like this (it includes conversion from degrees to radians):

ts
const RADIUS = 6378137.0;

function degreesToMeters(lat: number, lng: number) {
  return {
    x: (RADIUS * lng * Math.PI) / 180.0,
    y: RADIUS * Math.atanh(Math.sin((lat * Math.PI) / 180.0)),
  };
}

If you want to convert back, from meters to degrees, here is an inverted function:

λ=xaϕ=arcsin⁡(tanh⁡ya)\lambda = \frac{x}{a} \\ \phi = \arcsin\left(\tanh\frac{y}{a}\right)
ts
function metersToDegrees(x: number, y: number) {
  return {
    lng: ((x / RADIUS) * 180.0) / Math.PI,
    lat: (Math.asin(Math.tanh(y / RADIUS)) * 180.0) / Math.PI,
  };
}

Cool resources