[GIS] Converting GeoJSON pixel coordinates to lat long coordinates for use with Google Maps API

geojsongoogle-maps-apisvgwell-known-text

The entire process is quite a bit more complex than the question, so let me briefly describe it:

An SVG overlay of map features is parsed.

Each path is converted to WKT using SVG-to-WKT and then parsed into a GeoJSON Polygon by Terraformer.

The coordinates of that Polygon are each converted from pixel values to latitude and longitude using the below function pixelToLatLng (I forgot which article I derived that from). The pixel size was completely arbitrary and I don't particularly like that solution, especially as I haven't tested with other SVGs.

function pixelToLatLng(coords) {
    var pixelSize = 0.00002;
    var upperLeftCoord = [151.3358, -32.6615]; // Reference point for SVG viewbox
    var x = upperLeftCoord[0] + (parseFloat(coords[0]) * pixelSize);
    var y = upperLeftCoord[1] + (parseFloat(coords[1]) * pixelSize);
    return [x, y];
}

These values are used to create a Feature and in turn a FeatureCollection which is then added to a Google Maps data layer.

The issue is that the drawn data layers are slightly stretched vertically. I realise this is due to the mercator projection, but I'm having trouble determining what I need to convert and at what point I should do it.

Best Answer

Thanks to your expanded comments, I think I found the culprit.

I'll give you my reasoning, as well as a tl;dr in the last paragraph:

If the svg "just fits" when loading it into google maps, then the drawing has very likely been made using the same projection as a source.

I assume the SVG viewbox to be the troublemaker here. You already correctly realized that using an arbitrary pixelSize that "seems to fit" is suspect, as well. It certainly always is odd when dealing with geographic projections.

You indicate [151.3358, -32.6615] as the upper left coordinate for the viewbox. This is odd (why would it be negative?). A quick lookup tells me that if I read this is as a LatLng coord, it'll be in the middle of New York (possible your area of interest?). So the SVG viewbox seems to have been used by your 3rd party creator to take care of the "geographic" transformation.

To properly replicate this, you will need to consider the entire svg viewbox.

SVG uses the viewbox to automatically transform all its contents (relocate & stretch). I assume all your paths are inside this viewbox.

Solution: Check the dimensions of your viewbox. It should have four values: x, y, width, height Calculate the pixel size from that! I'm fairly certain you will see that your viewbox is not a square, but a rectangle. You can use that to calculate the horizontal and vertical scale of your svg. Then, having the proper no-longer-square pixels, you just need to apply the scale to fit your geographic target area (what's the extent North-South and West-East?) which will be the multiplier that you need to use for your code snippet.

function pixelToLatLng(coords, scale_x, scale_y) {
    var upperLeftCoord = [151.3358, -32.6615]; // Reference point for SVG viewbox
    var x = upperLeftCoord[0] + (parseFloat(coords[0]) * scale_x);
    var y = upperLeftCoord[1] + (parseFloat(coords[1]) * scale_y);
    return [x, y];
}

What you have now is a (very simple) affine transformation, a common reprojection technique.