Longitude to metres ratio given a latitude for Google Maps Static API stitching

coordinate systemgoogle mapsgoogle-maps-apilatitude longitude

I'm working on a project that hopes to convert Google Maps static images into larger, stitched together maps.

I have created an algorithm that given a starting and ending, latitude and longitude, it will fetch the Google Maps Static image for that lat,lng pair, then increment lng by the pixel width of the fetched image, in this case 700px, using an algorithm for determining pixel to longitude ratio using a couple of formulas.

The formulas seem to be working perfectly for latitude, as you can see in my attachment, the vertically tiling images line up almost perfectly.

Yet horizontally, the longitude increment seems to be off by a factor of 2, or slightly more.

To increment latitude, I use a constant metres to latitude ratio

const metresToLatRatio = 0.001 / 111 // Get lat value from metres
const metresPerPxLat = getMetresPerPxLng(currentLat, zoom)
const latIncrement = metresToLatRatio * (metresPerPxLat * 700)

But for longitude, I replace the metresToLngRatio constant with a variable derived from this formula

const metresToLngRatio = getMetresToLngRatio(currentLat)
const metresPerPxLng = getMetresPerPxLng(currentLat, zoom)
lngIncrement = (metresToLngRatio * (metresPerPxLng * 700))

Where getMetresToLngRatio and getMetresPerPxLng are

function getMetresPerPxLng(lat, zoom = 19, scale = 2) {
    return Math.abs((156543.03392 * Math.cos(lat * Math.PI / 180) / (2 ** zoom)) / scale)
}

function getMetresToLngRatio(lat) {
    return 1 / Math.abs(111111 * Math.cos(lat))
}

The getMetresPerPxLng function is derived from this post and this answer: https://groups.google.com/g/google-maps-js-api-v3/c/hDRO4oHVSeM / What ratio scales do Google Maps zoom levels correspond to?

What I noticed is that if I change getMetresToLng Ratio to return (1 / Math.abs(111111 * Math.cos(lat))) * 2, the stitching appears more accurate, only off by a few tens of pixels, instead of almost half the image.

With * 2
With times 2

Without * 2
Without times 2

Am I doing something wrong with my longitude equation? I know that 111111*cos(lat) is a rough estimate, so I'm wondering if there's a more accurate formula.

Best Answer

"Longitude versus pixel" increments seems to me the same at all the globe, so do not use the cosine of latitude for them (you don't need the "real" distance, just the longitude).

The latitude increment is OK if you fix the "degrees per meter at the equator" ratio (360/(2.π.6378137)).

So in my opinion it should be something like the following:

const degreesPerMeterAtEquator = 360 / (2 * Math.PI * 6378137)

const metresAtEquatorPerTilePx = 156543.03392 / (2 ** zoom)

const latIncrement = degreesPerMeterAtEquator * Math.cos(currentLat * Math.PI / 180) * metresAtEquatorPerTilePx * 700
const lonIncrement = degreesPerMeterAtEquator * metresAtEquatorPerTilePx * 700

A multiplier is required to make tiles seamless for some reason Seen here perfectly tiling at latitudes and longitudes over 60 degrees apart. Australia and America:

enter image description here

enter image description here

const degreesPerMeterAtEquator = 360 / (2 * Math.PI * 6378137)

const metresAtEquatorPerTilePx = 156543.03392 / (2 ** zoom)

const multiplier = 0.915

const latIncrement = (degreesPerMeterAtEquator * Math.cos(currentLat * Math.PI / 180) * metresAtEquatorPerTilePx * 700) * multiplier
const lonIncrement = (degreesPerMeterAtEquator * metresAtEquatorPerTilePx * 700) * multiplier
Related Question