# Using Log Math to Solve Iterative Problems

**Premise**: You have a map of infinite resolution, but finite viewing space. You have points on that map that have a fixed foot print.

**Question**: How much do you need to zoom before the points are clearly distinguishable?

Let us arbitrarily define the *criteria for distinguishability* as an icon of 25 pixels in size. This icon, it can be said, has a radius of 13 pixels. In reality, icon size is a function of your viewport’s size. I leave that up to you to calculate.

Let us define the *scale of the map* as the absolute width of the map (in map units) divided by the width of the view port. As an example, let’s use the Earth’s longitude range: -180 to +180 degrees, but in a global Mercator projection. The coordinate range of longitude for this map is [-20037508,+20037508) meters. Our viewport has a range of [0,255] pixels (viewport units). The scale of this map in this viewport is (2*20037508)/256. Be careful not to double-count +20037508, as -20037508 = +20037508 and would yield an improper scale. The viewport size is an integer and does not wrap; there are no fractions of a pixel in a viewport.

We shall now define a *target scale*. The target scale is the desired scale of the map that allows our icons to become viewable. Our example will use buildings having a foot print of 300 meters (map units) in width and depth. Our target scale, therefore, is 300/25 = 12 meters per pixel.

**Question**: How much do we need to zoom in before our buildings are distinguishable?

**Implementation** 1 (naive, iterative):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function zoomLevel( $maprange, $viewport, $distFactor=0.10, $zoomFactor=2 ) { // $viewport = 256; // $maprange = 2*M_PI*6378137; $scale = $maprange / $viewport; // 10% of viewport required to distinguish an icon. $target = $distFactor * $viewport; $zoom = 0; while ( $scale > $target ) { $zoom += 1; $scale /= $zoomFactor; } return $zoom; } |

**Implementations** 2, 3 and 4:

1 2 3 4 5 6 7 8 9 10 11 12 13 | function zoomLevel( $maprange, $viewport, $distFactor=0.10, $zoomFactor=2 ) { $scale = $maprange / $viewport; $target = $distFactor * $viewport; // naive log return ceil( (log($scale)/log($zoomFactor) - log($target)/log($zoomFactor)) ); // commutative log return ceil( (log($scale) - log($target)) / log($zoomFactor) ); // subtraction property of logs (best implementation) return ceil( log($scale/$target)/log($zoomFactor) ); } |