[GIS] How to “calculate” distance-to-ground of all 18 OSM zoom levels

3dcoordinate systemmathematicsopenstreetmap

Assuming I'm building a 3D solution with the "world" being mapped to global geo-data supplied by OSM / Cloudmade… think http://www.webglearth.com but with completely different goals and use-cases. In fact we won't have a round sphere but only work off a "flat" (+ elevation later) surface/ground plane at all times.

Now assume further that we want to texture the "visible" fragments of the "ground" plane with OSM and/or Bing/MapQuest/Google aerial map tiles, the level of detail / zoom level to be chosen based on the "camera's" / viewer's "altitude" / distance-to-ground — say in meters.

Knowing that 1. we only use OSM-equivalent tiles using exactly the same spherical mercator projection (which, from what I gather, is used by all the major map players ie. OSM, Google, Bing) and hence 2. always equivalent scale-distortions depending on latitude: how can I decide which zoom level to switch to when viewer altitude changes?

Of course the boundary cases are easy: zoom level 18 is to be used on-or-close-to-the-ground and zoom level 0 from "outer space". But the intermediate cases are a mystery to me when it comes to figuring out "from which altitude they had been taken if they were simple photos", so to speak.

I saw this page http://wiki.openstreetmap.org/wiki/Zoom_levels and some related pages but nowhere did I find an approximation on how to "map" a fictive altitude to a zoom level.

Best Answer

Some ideas that can help you:

  1. Web tile has a certain resolution (PPI, pixels per inch). You probably want to avoid displaying the tile as a texture that looses a lot of PPI. So a tile that is 256x256 probably wouldn't look too good shown as a 1024x1024 texture.
  2. Each OSM zoom level has its own (approximate) map scale.
  3. Since you say you'll show a flat Earth, you can still calculate the current map scale based on the distance of the observer from the Earth, the latitude the observer is on and the size of the screen.
  4. Once you have the current map scale, you can calculate the zoom level (code taken from my project Maperitive):

    public static float MapScaleToOsmZoomLevel(float mapScale, float latitude, float ppi)
    {
        const float MetersPerInch = 2.54f / 100;
    
        const double EarthCircumference = EarthRadius * Math.PI * 2;
        double realLengthInMeters = EarthCircumference * Math.Cos (Deg2Rad (latitude));
    
        double zoomLevelExp = (realLengthInMeters*ppi) / (256*MetersPerInch*mapScale);
    
        return (float) Math.Log(zoomLevelExp, 2);
    }
    

Now you have a zoom level as a real value and you can calculate the actual zoom level based on a "quality" setting - for example if you want a higher quality, you can use something like Math.Ceiling(zoom).