MKTileOverlay with gdal2tiles or other TMS tiles

Mon, 24. Aug 2015

Categories: en development Tags: gdal gdal2tiles iOS Map MKTileOverlay Overlay Objective C Tile

from iOS 7.0 onward there’s the neat MKTileOverlay::initWithURLTemplate: for tiled overlay maps.

Sadly it can’t display old-school Tile Map Service maps as e.g. produced by gdal2tiles.py1) because the y-values are flipped upside down. The OSM Wiki says about this fact: „This is really just an unfortunate historical misalignment.“

But with the drop-in MKTileOverlay replacement below, you can use flipped geometries and add {-y} in the URL template to indicate such:

#import 
// Copyright (c) 2015 Marcus Rohrmoser http://mro.name/me. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see .

// interface unchanged
@interface MKTileOverlayOSMorTMS : MKTileOverlay
@end

/**
 * OSM: http://wiki.openstreetmap.org/w/index.php?title=Slippy_map_tilenames&oldid=1201902#X_and_Y
 * TSM: http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
 *
 * http://wiki.openstreetmap.org/w/index.php?title=Slippy_map_tilenames&oldid=1201902#Tile_numbers_to_lat..2Flon._.2F_Coordinates_to_tile_numbers_.2F_Sample_of_usage.2C_with_optional_tms-format_support
 * const MKTileOverlayPath p0 = { x : 70406, y : 42987, z:17 };
 * const MKTileOverlayPath p1 = convertYfromOSMtoTMS(p0);
 * assert(88084 == p1.y && "");
 */
static inline MKTileOverlayPath convertYfromOSMtoTMS(MKTileOverlayPath path)
{
  assert( (1 << path.z) == (NSInteger)pow(2, path.z) && "oops, pow failed" );
  path.y = (1 << path.z) - 1 - path.y;
  return path;
}

@implementation MKTileOverlayOSMorTMS

/** Detect `{-y}` in case and set `geometryFlipped` accordingly.
 */
-(instancetype)initWithURLTemplate:(NSString *)URLTemplate
{
  NSString *t = [URLTemplate stringByReplacingOccurrencesOfString:@"{-y}" withString:@"{y}"];
  if( self = [super initWithURLTemplate:t] ) {
    // NSParameterAssert(256.0f == self.tileSize.width);
    NSParameterAssert(256.0f == self.tileSize.height);
    NSParameterAssert(t.length == URLTemplate.length || t.length + 1 == URLTemplate.length);
    self.geometryFlipped = t.length < URLTemplate.length;
  }
  return self;
}

-(NSURL *)URLForTilePath:(MKTileOverlayPath)path
{
  if( self.geometryFlipped ) {
    // NSParameterAssert(256.0f == self.tileSize.width);
    NSParameterAssert(256.0f == self.tileSize.height);
    path = convertYfromOSMtoTMS(path);
  }
  MRLogD(@"%ld,%ld,%ld", (long)path.z, (long)path.x, (long)path.y, nil);
  return [super URLForTilePath:path];
}
@end

1) see also the debian package python-gdal or the webpage of Petr Přidal, the author of gdal2tiles with a hint to it’s commercial successor.