0

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.

2
  • Haversine Distance Formula stackoverflow.com/questions/14560999/… will be more accurate.
    – Mapperz
    Jan 28 at 15:57
  • I'm not thinking too clearly yet this morning but maybe try 111319(.49) which is closer to length of 1 degree at the equator for a radius of 6378137.
    – mkennedy
    Jan 29 at 20:42

1 Answer 1

0

"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
7
  • You are actually right, the Google map has been flattened using Mercator so all longitude and latitude increments should be the same constant. I will give it a go thank you. I suspect that Google has added some randomisation because upon trying this I need to tweak the pixel to degrees formula ever so slightly to get seamless tiling with the same values at places over 20 degrees apart...
    – lopu
    Jan 30 at 22:20
  • Latitude increments are not constant. Each pixel measures a different amount of degrees in latitude. So using one value for 700 pixels is a reduction. 20 degrees apart seems to be a considerable amount to take it into account. Jan 30 at 23:15
  • I don't think there is such randomization. The tiles coordinate system does not take into account increments in meters or degrees, only in pixels. I suppose it would be more accurate to directly request the 256x256 pixel tiles by their coordinates (not the geographic ones). But I don't know what functionalities the API has or the working model of your project. Assume that my answer is accurate if the increments are considered only for the central pixel of each image. Jan 30 at 23:26
  • Wait, longitude increments are constant, and latitude are variable? I thought it would be the other way around as longitude is the one being stretched and etc right? Thanks heaps for the comments, still haven't had time to try out your formulas but give me a couple hours.
    – lopu
    Jan 31 at 6:58
  • 1
    Ohhhh because latitude is a curve which is being flatted to a line, the curve will distort latitude to pixel ratio more towards the poles. But longitude isn't affected I seeeeeeeeee. I thought that mercator creates a totally even grid in terms of pixels for latitude and longitude, but it doesn't I see. For example see: upload.wikimedia.org/wikipedia/commons/7/70/… Thank you so much And yes, the API does not allow getting a tile via a pixel coordinate, thus requiring this conversion logic
    – lopu
    Jan 31 at 7:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.