3

I'm creating a Leaflet map with an WebGL overlay (using L.CanvasOverlay) which renders a street network on the GPU.

Let's assume I have a point (1497143.62, 6896952.18) in EPSG:3857 and want to transform it to a pixel coordinate on a 256x256 raster, similar to a google maps tile at zoom level 0 (compare: this and that).

I can convert the same point (52.51904, 13.44907) to EPSG:4326 and use the following JavaScript code to do the reprojection to the 256x256 tile raster:

/**
 * Converts Lat/Lon to tile pixel X/Y at zoom level 0 
 * for 256x256 tile size and inverts y coordinates.
 *
 * @param {float} lat Latitude
 * @param {float} lon Longitued
 * @return Point with x and y corrdinates.
 */
function latLonToPixels(lat, lon) {
    var sinLat = Math.sin(lat * Math.PI / 180.0);
    var pixelX = ((lon + 180) / 360) * 256;
    var pixelY = (0.5 - Math.log((1 + sinLat) / (1 - sinLat)) / (Math.PI * 4)) * 256;
    return { x: pixelX, y: pixelY };
}

... which leaves me with the desired point (137.56378, 83.94214) on the raster.

So, using leaflet I could transform my point from 3857 to 4326 and afterwards calculate the pixel coordinates using the formula above. But as I understand the forumlas, this would require two spherical reprojections which is jus too much computing for large geometries.

I suspect there is a much more simple and efficient approach for this transformation. But I couldnt figure it out yet. Any idea?

In addition, searching the internet I can't figure out what the EPSG:3857 coordinates actually denote. This and that answer try to explain it a bit but it is still unclear how to programmatically solve this.

4

This is the answer. Sometimes you have to go through all the process of asking a question to understand the solution. JavaScript:

/**
 * Converts spherical web mercator to tile pixel X/Y at zoom level 0 
 * for 256x256 tile size and inverts y coordinates.
 *
 * @param {L.point} p Leaflet point in EPSG:3857
 * @return {L.point} Leaflet point with tile pixel x and y corrdinates.
 */
function mercatorToPixels(p)  {
  var equator = 40075016.68557849;
  var pixelX = (p.x + (equator / 2.0)) / (equator / 256.0);
  var pixelY = ((p.y - (equator / 2.0)) / (equator / -256.0));
  return L.point(pixelX, pixelY);
}

Explanation

The tile at zoom level 0 has a size of 40,075,016m * 40,075,016m. The tile size is 256px * 256px. The center of the web mercator is (0, 0).

  1. Translate the X-coordinate by a positiv half equator.
  2. Divide the X-result by the positive pixel size in meter.
  3. Translate the Y-coordinate by a negative half equator.
  4. Divide the Y-result by the negative pixel size in meter.

That's it.

  • Please mark it as answer, even though it is yourself (everyone does that, duck typing :) ). – bugmenot123 Jul 9 '15 at 12:39
  • 1
    @bugmenot123 i can not mark my own answer as accepted within 48h after asking the question, but thanks for the heads up. – Waqar Lim Jul 10 '15 at 9:53
1

I would look into using the proj4.js library to transform your coordinates programatically using javascript. From the Github Readme:

Basic usage: proj4(fromProjection[, toProjection2, coordinates])

eg:

```

var firstProjection = 'PROJCS["NAD83 / Massachusetts Mainland",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",42.68333333333333],PARAMETER["standard_parallel_2",41.71666666666667],PARAMETER["latitude_of_origin",41],PARAMETER["central_meridian",-71.5],PARAMETER["false_easting",200000],PARAMETER["false_northing",750000],AUTHORITY["EPSG","26986"],AXIS["X",EAST],AXIS["Y",NORTH]]';

var secondProjection = "+proj=gnom +lat_0=90 +lon_0=0 +x_0=6300000 +y_0=6300000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";

//I'm not going to redefine those two in latter examples.
proj4(firstProjection,secondProjection,[2,5]);
// [-2690666.2977344505, 3662659.885459918]
  • 1
    It's either not answering my question or so badly explained that I don't understand what you are suggesting, sorry. – Waqar Lim Jul 10 '15 at 9:55
  • wow @donSchoe thanks for down voting my answer when I was attempting to be helpful. I realize now that you weren't looking for a library, mis-read your question. I linked to the documentation so don't see how that's "poorly explained". No need to be a jerk. – clhenrick Jul 10 '15 at 14:56
  • 1
    No offense intended. I just don't get it. – Waqar Lim Jul 14 '15 at 7:57

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.