title: Common Mercator Projection formulas for Google Maps not working correctly
body: <p>I am building a Tile Overlay server for Google maps in C#, and have found a few different code examples for calculating Y from Latitude.  After getting them to work in general, I started to notice certain cases where the overlays were not lining up properly.  To test this, I made a test harness to compare Google Map's Mercator LatToY conversion against the formulas I found online.  As you can see below, they do not match in certain cases.</p>
  
  <p><strong>Case #1</strong></p>
  
  <blockquote>
    <p>Zoomed Out:  The problem is most
    evident when zoomed out.  Up close,
    the problem is barely visible.</p>
  </blockquote>
  
  <p><strong>Case #2</strong></p>
  
  <blockquote>
    <p>Point Proximity to Top &amp; Bottom of
    viewing bounds:  The problem is worse
    in the middle of the viewing bounds,
    and gets better towards the edges. 
    This behavior can negate the behavior
    of Case #1</p>
  </blockquote>
  
  <p>The Test:</p>
  
  <blockquote>
    <p>I created a google maps page to
    display red lines using the Google Map
    API's built in Mercator conversion,
    and overlay this with an image using
    the reference code for doing Mercator
    conversion.  These conversions are
    represented as black lines.  Compare
    the difference.</p>
  </blockquote>
  
  <p>The Results:
  <a href="http://www.kayak411.com/Mercator/MercatorComparison%20-%20Equator.png">Equator http://www.kayak411.com/Mercator/MercatorComparison%20-%20Equator.png</a>
  <a href="http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Out.png" title="North Zoomed Out">North Zoomed Out http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Out.png</a></p>
  
  <p>Check out the top-most and bottom-most lines:
  <a href="http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Out%20-%20TopAndBottom.png" title="North Top &amp; Bottom Example">North Top &amp; Bottom Example http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Out%20-%20TopAndBottom.png</a></p>
  
  <p>The problem gets visually larger but numerically smaller as you zoom in:
  <a href="http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Midway.png" title="Medium Zoom Level">alt text http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20Midway.png</a></p>
  
  <p>And it all but disappears at closer zoom levels, regardless of screen orientation.
  <a href="http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20In.png" title="Zoomed In">alt text http://www.kayak411.com/Mercator/MercatorComparison%20-%20North%20Zoomed%20In.png</a></p>
  
  <p>The Code:</p>
  
  <p>Google Maps Client Side Code:</p>
  
  <pre><code>            var lat = 0;
          for (lat = -80; lat &lt;= 80; lat += 5) {
              map.addOverlay(new GPolyline([new GLatLng(lat, -180), new GLatLng(lat, 0)], "#FF0033", 2));
              map.addOverlay(new GPolyline([new GLatLng(lat, 0), new GLatLng(lat, 180)], "#FF0033", 2));
          }
  </code></pre>
  
  <p>Server Side Code:</p>
  
  <blockquote>
    <p>Tile Cutter : 
    <a href="http://mapki.com/wiki/Tile_Cutter">http://mapki.com/wiki/Tile_Cutter</a></p>
    
    <p>OpenStreetMap Wiki :
    <a href="http://wiki.openstreetmap.org/wiki/Mercator">http://wiki.openstreetmap.org/wiki/Mercator</a></p>
  </blockquote>
  
  <pre><code> protected override void ImageOverlay_ComposeImage(ref Bitmap ZipCodeBitMap)
          {
              Graphics LinesGraphic = Graphics.FromImage(ZipCodeBitMap);
  
              Int32 MapWidth = Convert.ToInt32(Math.Pow(2, zoom) * 255);
  
              Point Offset =
                  Cartographer.Mercator2.toZoomedPixelCoords(North, West, zoom);
  
              TrimPoint(ref Offset, MapWidth);
  
              for (Double lat = -80; lat &lt;= 80; lat += 5)
              {
                  Point StartPoint = Cartographer.Mercator2.toZoomedPixelCoords(lat, -179, zoom);
                  Point EndPoint = Cartographer.Mercator2.toZoomedPixelCoords(lat, -1, zoom);
  
                  TrimPoint(ref StartPoint, MapWidth);
                  TrimPoint(ref EndPoint, MapWidth);
  
                  StartPoint.X = StartPoint.X - Offset.X;
                  EndPoint.X = EndPoint.X - Offset.X;
  
                  StartPoint.Y = StartPoint.Y - Offset.Y;
                  EndPoint.Y = EndPoint.Y - Offset.Y;
  
  
                  LinesGraphic.DrawLine(new Pen(Color.Black, 2),
                      StartPoint.X,
                      StartPoint.Y,
                      EndPoint.X,
                      EndPoint.Y);
  
                  LinesGraphic.DrawString(
                      lat.ToString(),
                      new Font("Verdana", 10),
                      new SolidBrush(Color.Black),
                      new Point(
                          Convert.ToInt32((width / 3.0) * 2.0),
                          StartPoint.Y));
              }
          }
  
          protected void TrimPoint(ref Point point, Int32 MapWidth)
          {
              point.X = Math.Max(point.X, 0);
              point.X = Math.Min(point.X, MapWidth - 1);
  
              point.Y = Math.Max(point.Y, 0);
              point.Y = Math.Min(point.Y, MapWidth - 1);
          }
  </code></pre>
  
  <p>So, Anyone ever experienced this?  Dare I ask, resolved this?  Or simply have a better C# implementation of Mercator Project coordinate conversion?</p>
  
  <p>Thanks!</p>