Apr 30, 2010 at 6:44 PM


I am trying to load tiles from WMS server, which are in WGS84 projection. I'm modifying the

MakeImageUrl(MapType type, Point pos, int zoom, string language)

function. I succeed getting some coordinates from the tile number through this code:

                     Point tilePoint = new Point(pos.X * 256, pos.Y * 256);
                     int pixelsPerRow = 256 * (int)Math.Pow((double)2.0, (double)zoom);

                     double resX = (double)(360 / (double)pixelsPerRow);
                     double resY = (double)(180 / (double)pixelsPerRow);
                     PointLatLng pntLatLng1 = new PointLatLng(tilePoint.X * resX - 180, 90 - ((tilePoint.Y * resY) + (256 * resY)));
                     PointLatLng pntLatLng2 = new PointLatLng(tilePoint.X * resX - 180 + 256 * resX, 90 - tilePoint.Y * resY);

I'll try to explain. First, we have 256x256px tiles and through tilePoint we get the top-left position of the tile. After that, we get the overall number of pixels according to the Zoom level (pixelsPerRow = pixelsPerColumn, because it's map 256x256px tiles and the number of tiles are (4^zoom) for each zoom level, (2^zoom) number of tiles on a row/column, starting from 0).

Then we make resolution doubles, resX, resY and we get the number of degrees for each pixel.

Then, for WMS (official documentation) we need bottom-left and top-right points of the tile, to extract the information from the server, in Lat/Lng. So, we make pntLatLng1 (bottom-left) and pntLatLng2 (top-right) points. I'm sure the code is generating right points, but the tile I get is not very "well-shaped". I mean, it is a little "elongated" to the poles. I think it's something to do with the "geoidic" shape of the earth. =]

Am I correct, and can someone give directions, how to make the code "right".

These are the WGS84 settings:

radius a = 6,378,137 m at the equator

minor (conjugate) radius b = 6,356,752.314 245 m at the poles

flattening of 21.384 685 755 km, or 1/298.257 223 563 ≈ 0.335%

Thanks in advance!

Many thanks for the great project! =]

May 1, 2010 at 10:19 AM


May 3, 2010 at 8:44 AM

Hello again,

I know why that was happening - it's because the pixels are 256x256, and the degrees are 360x180, so the wms server is giving me transformed jpeg, much flattened and the markers aren't where they have to be. From zoom level 1, where I have 2x2 tiles, I can render the world on the top 2 tiles, but what projection should I use, and has anyone had similar problem?


May 3, 2010 at 9:18 AM

there are few projections, each map provider use different, so which is yours?

May 3, 2010 at 9:33 AM
Edited May 3, 2010 at 11:13 AM

It's WGS 84. I can give you URL to see what exactly happens.

On the GMaps, it shows like this:

while it should be like this:



EDIT: Hm, I'll try to add a new projection class with tile size 512x256. =]

May 3, 2010 at 12:42 PM

mm, so the there is error in calculating pixels somewhere... Can you make fork with something you already done?

May 4, 2010 at 11:14 AM
Edited May 4, 2010 at 11:59 AM

yes, in a minute



Heres a fork to test the changes.

May 4, 2010 at 2:03 PM
Edited May 4, 2010 at 2:59 PM

i see, well there is projection mismatch, i think you use really PlateCarreeProjection, like ArcGIS, on free minute i'll try to figure it out ;}

p.s. i almost got it

May 4, 2010 at 3:16 PM
Edited May 4, 2010 at 3:19 PM

you were right about the first thing, modifying the code like this:


                     Point tilePoint = new Point(pos.X * 256, pos.Y * 256);
                     int pixelsPerRow = 256 * (int)Math.Pow((double)2.0, (double)zoom);

                     double resX = (double)(360 / (double)pixelsPerRow);
                     //double resY = (double)(180 / (double)pixelsPerRow);
                     PointLatLng pntLatLng1 = new PointLatLng((double)((double)tilePoint.X * resX - (double)180), 180 - ((tilePoint.Y * resX) + (256 * resX)));
                     PointLatLng pntLatLng2 = new PointLatLng(tilePoint.X * resX - 180 + 256 * resX, 180 - tilePoint.Y * resX);

                     return string.Format("http://localhost:8081/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=Test Workspace:world&styles=&bbox={0},{1},{2},{3}&width=256&height=256&srs=EPSG:4326&format=image/jpeg", pntLatLng1.Lat.ToString(CultureInfo.InvariantCulture), pntLatLng1.Lng.ToString(CultureInfo.InvariantCulture), pntLatLng2.Lat.ToString(CultureInfo.InvariantCulture), pntLatLng2.Lng.ToString(CultureInfo.InvariantCulture));

i.e. now it's calculating pixels the right way =] thanks alot for the clue.. but it still isn't the right projection


May 4, 2010 at 7:35 PM
Edited May 5, 2010 at 8:28 AM

;}} few touches and it runs effing Great !!

  Projections.MercatorProjection ProjectionForWMS = new Projections.MercatorProjection();

  // Engage & enjoy ;}     

case MapType.WMSdemo:
   var px1 = ProjectionForWMS.FromTileXYToPixel(pos);
   var px2 = px1;

   px1.Offset(0, ProjectionForWMS.TileSize.Height);
   PointLatLng p1 = ProjectionForWMS.FromPixelToLatLng(px1, zoom);

   px2.Offset(ProjectionForWMS.TileSize.Width, 0);
   PointLatLng p2 = ProjectionForWMS.FromPixelToLatLng(px2, zoom);

   var ret = string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}&width={4}&height={5}&srs=EPSG:4326&format=image/png", p1.Lng, p1.Lat, p2.Lng, p2.Lat, ProjectionForWMS.TileSize.Width, ProjectionForWMS.TileSize.Height);

   return ret;

May 5, 2010 at 7:22 AM
Edited May 5, 2010 at 7:48 AM

It's beautiful... Easy and clean! =] Very grateful for the code... Now working on the rest ideas =] Thanks Thanks Thanks!



Heres a nice server: (heres a demo){0},{1},{2},{3}&width={4}&height={5}&srs=EPSG:4326&format=image/png

May 5, 2010 at 8:29 AM

perfect, i've changed it to MercatorProjection, looks even better ;}