Flyover mode in MapKit with WMS

Suprise, iOS 9 MapKit finally enables  flyeover mode with WMS overlays ! I have used my github  MapKit sample and only  set in MapViewController    mkMapView.mapType = MKMapTypeHybridFlyover;


Drawing Shape File on MapKit

Simple & strightforward test of loading shape file and drawing it on MapKit on iOS8 using drawMapRect



  • draws only polygons so far
  • primitive optimization, no scale optimisation

Reading of shape file is performed by shapelib

NS_INLINE NSArray *getPolygonsFromShapeFile(NSString *shpFilePath){
    const char *path = [shpFilePath cStringUsingEncoding:NSUTF8StringEncoding];
    SHPHandle shp = SHPOpen(path, "rb");
    int numEntities;
    int shapeType;
    SHPGetInfo(shp, &numEntities, &shapeType, NULL, NULL);
    NSMutableArray *allPolygons = [[NSMutableArray alloc]init];
    for (int i=0; i<numEntities; i++){
       SHPObject *shpObject = SHPReadObject(shp, i);
       if (shpObject->nSHPType == SHPT_POLYGON ||
           shpObject->nSHPType == SHPT_POLYGONZ ||
           shpObject->nSHPType == SHPT_POLYGONM){

            int numParts = shpObject->nParts;
            int totalVertexCount = shpObject->nVertices;

            for (int n=0; n<numParts; n++)
                int startVertex = shpObject->panPartStart[n];
                int partVertexCount = (n == numParts - 1) ? totalVertexCount - startVertex : shpObject->panPartStart[n+1] - startVertex;
                int endIndex = startVertex + partVertexCount;
                CLLocationCoordinate2D coords[partVertexCount];
                for (int pv = startVertex, i = 0; pv < endIndex; pv++,i++) {
                    coords[i] =CLLocationCoordinate2DMake(shpObject->padfY[pv],
                // -- this actually converts lat lon to mkmappoints projection
                MKPolygon *singlePolygon = [MKPolygon polygonWithCoordinates:coords count:partVertexCount];
                [allPolygons addObject:singlePolygon];
    return [allPolygons copy];


drawing :
parsing :

MapBox GL – vector map open source project

Open Source OpenGL vector map rendering called MapBox GL, introduced here.  Quick  test run on iPad Air was successful and is available here :

Quotes from the site:

“Mapbox GL is based on the same vector tile format that powers Mapbox Streets. This means that you can use our global basemap, fully or in part, as well as create your own vector tiles to interleave data from different sources. Much like in TileMill, our open source map design studio, you can create a custom map by composing the various roads, parks, water areas, buildings, and more from lines, points, and polygons, then style them flexibly.”

“We built Mapbox GL in C++11 using OpenGL ES 2.0, a subset of OpenGL that is available on mobile devices and that can also run on desktop hardware with very minor changes. We use protocol buffers via pbf.hpp to implement a lazy vector tile parser, plus we’ve implemented custom code for text display and layout.

Mapbox GL is open source under a permissive BSD license, so you can check out all of the code right now. It currently runs on iOS, OS X, and Linux.”

WMS on MapKit with iOS7

Updated WMS over MapKit sample code for iOS7 , available on github  I have added cadastral maps of Czech Republic, used camera API to set the view and tested, check also WMS on Google  Maps SDK on iOS mentioned here

iOS7 introduced new class MKTileOverlay sample derives from this class WMSTileOverlay

Key method to custom tile loading (and cache control) is loadTileAtPath:result

- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))  result

this method is called by MapKit (or better by MKTileOverlayRenderer ) when it needs to draw a tile . It asks for NSData (and error) from x,y,z tile coordinates. In this method you can  load NSData either from local cache or from NSURLConnection and pass resulting NSData (when ready)  back to MapKit, for example like this (reading from cache)

result ([NSData dataWithContentsOfFile:filePath], nil);

if you do not need to use cache and you do not provide loadTileAtPath method , you can use another hook (callback) that is provided by MKTileOverlay, URLForTilePath:path

- (NSURL *)URLForTilePath:(MKTileOverlayPath)path

this method enables to custom format URL required to load tile, thus you can use WMS HTTP-GET parameters, for example :

NSString * resolvedUrl = [NSString stringWithFormat:@"%@&BBOX=%f,%f,%f,%f",self.url,left,bottom,right,top];

if there is neither method in the derived class, then you probably do not need to derive at all from MKTileOverlay and directly use it with initWithUrlTemplate (not case for WMS, but for any other x,y,z  sources)


Bad news is that  MapKit on iOS7 doesn’t support   tilt/pinch in Satellite/Hybrid mode in MapKit on iOS7

WMS with Google Maps on iOS

Screen Shot 2014-04-21 at 00.49.02Sample for using WMS sources in Google Maps SDK for iOS. available on github here:
Provide your API key in the WMSController.h

  • Google Maps for iOS used : 1.7.2 (April 2014)
  • used XCode 5.1.1 (April 2014)
  • iPad Air, iOS 7.1 (should run in iOS6.0 too)


There are two ways of overlaying WMS in the Google Maps for iOS SDK:

“Method B”: use GMSTileURLConstructor

   // -- method B. WMS tile layer with GMSTileURLConstructor
      GMSTileURLConstructor urls = 
         ^(NSUInteger x, NSUInteger y, NSUInteger z) {
           BBox bbox = bboxFromXYZ(x,y,z);
           NSString *urlKN = 
             [NSString stringWithFormat:@"Your WMS url&BBOX=%f,%f,%f,%f",

          return [NSURL URLWithString:urlKN];

“Method A”: use custom TileLayer derived from GMSTileLayer

  1. your derived class from GMSTileLayer (here WMSTileLayer.h) will receive tile request
  2. WMSTileLayer first checks for cached tile and if found calls :
      [self drawTileAtX:x y:y zoom:z Url:urlStr Receiver:receiver] ;
  3. if tile is not cached we download it, save it to the file system (using MD5 hash) and call to draw it
      [data  writeToFile: filePath  atomically:YES];
      [self drawTileAtX:x y: y zoom: z Url:urlStr Receiver:receiver] ;
  4. drawTileAtX is very simple:
      -(void) drawTileAtX: (NSUInteger) x 
                                   y:(NSUInteger) y
                                 Url:(NSString*) url
                            Receiver: (id<GMSTileReceiver>) receiver {
           UIImage             *image   = TileLoad(url,NO); 
           [receiver receiveTileWithX:x y:y zoom:zoom image:image]; 


both ways are used in this sample.

From .NET to iOS developer

What it takes to transfer from Microsoft .NET to Apple iOS  developer ?

Update 2015: more longer and similar story/explanation  found  here


So this was me ‘before’ with all my friends:  Windows, C#, .NET, Visual Studio, MSDN :

– easy ‘managed’ life,
– can smile and make ceremony
– implicit friends and friends of friends you can’t get rid of them
– shallow water, no deep dive
– few freezes
– slightly detuned, but good enough for many
– moon shots

…and me ‘after’  passing through the  fire of iOS, Objective-C, Cocoa Touch, XCode, Documentation, Mac, Certificates, AppStore

– different game, different rules
– lot of explosive material (resources)
– focused, not distracted by ‘friends’
– intelligence and luck needed
– dangerous and too explicit
– very rewarding



Instantiate view on iOS with mix of XIB and View class

How avoided storyboard and overloading XIB with just right split between what is visually defined and what is programatically programmed:

  1. visual set-up of the view in Interface builder – only view, no controllers and setting up outlets but no actions. AddNoteView.xib . Justify controls, set up autoscaling etc..
  2. create AddNoteView.h with outlets
  3. create AddNoteView.m and hook awakeFromNib and setup additional settings on view- (void)awakeFromNib{

    [super awakeFromNib];

    CALayer * layer = [self.locationThumb layer];

    [layer setMasksToBounds:YES];

    [layer setCornerRadius:10.0];

  4. create AddNoteViewController.m and define loadView- (void)loadView {

    self.view =  [[UINib nibWithNibName:@”AddNoteView” bundle:nil]  instantiateWithOwner:nil options:nil][0];