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.

TomazicM
  • 25,601
  • 22
  • 29
  • 39
lopu
  • 5
  • 3
  • Haversine Distance Formula https://stackoverflow.com/questions/14560999/using-the-haversine-formula-in-javascript will be more accurate. – Mapperz Jan 28 '22 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 '22 at 20:42

1 Answers1

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

MrXsquared
  • 34,292
  • 21
  • 67
  • 117
Gabriel De Luca
  • 14,289
  • 3
  • 20
  • 51
  • 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 '22 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. – Gabriel De Luca Jan 30 '22 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. – Gabriel De Luca Jan 30 '22 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 '22 at 06: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: https://upload.wikimedia.org/wikipedia/commons/7/70/Mercator_projection_of_world_with_grid.png

    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 '22 at 07:03
  • You will be pleased to hear your formulas have worked (almost) perfectly to increment longitude and latitude at any degree. The odd part was I had to multiply both the lat and lng final computed increment values by 0.915. See results here of latitudes and longitudes over 60 degrees apart, Australia and USA: https://imgur.com/a/Kulhr0s

    Any idea why this might be?

    – lopu Jan 31 '22 at 08:18
  • I'm glad they worked! I have no idea what the multiplier is due to. – Gabriel De Luca Jan 31 '22 at 12:34