MapKit with ARKit and overlays

Flyover mode in Apple Maps allows  AR/VR style interaction.  This is not by default available for iOS developers using underlaying MapKit/ARKit technology.  However it is possible to test it and the following short video is about this proof of concept – viewing cadastral maps (iKatastr)  in VR like experience on iPad .  Btw. Flyover mode on iOS 11  has some strange handling of overlays – described here so loading of tiles is little bit tricky. The iOS 10 version was much more better (check the video here)

 

3D visual interactive analysis with myVR SDK

Recent weeks I have been working on the concept code named ‘Impact IN’  where I could apply few interesting ideas of the modern, interactive 3D  geospatial analysis. The core 3D functionality and viewshed analysis is provided by myVR SDK . While this concept is demonstrated  on iPad Pro with iOS , myVR SDK  is truly multi-platform SDK so this can be run on any platform (Android, Web, Desktop, it runs even on Daqri helmet!). I have used Apple Pencil to navigate directional viewshed and to drive fly-through on 3D map  – it works like joystick. Another concept  shown here is the real-time transition of the analysis from 3D to 2D – so while user interacts with the viewshed on 3D city model  of London , it is at the same time reflected on 2D map, creating thematic map of the impacted areas – a classic GIS result that can undergo further analysis in a GIS system of choice, or better go directly as input into the Smart M.App    (e.g. into Studio or Grid Analysis)….  following video is what attendees could see at HxGN Live 2017 . [will continue next time]

Drawing Shape File on MapKit

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

GitHub:https://github.com/Sumbera/SHPonMapKit

 

  • 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],
                                                          shpObject->padfX[pv]);
                }
                // -- this actually converts lat lon to mkmappoints projection
                MKPolygon *singlePolygon = [MKPolygon polygonWithCoordinates:coords count:partVertexCount];
                [allPolygons addObject:singlePolygon];
            }
       }
       
     SHPDestroyObject(shpObject);
       
  }
    SHPClose(shp);
    
    return [allPolygons copy];
}

credits/inspiration:

drawing : http://stackoverflow.com/questions/17673410/mkmapview-with-multiple-overlays-memory-issue
parsing : http://www.al-tyus.com/blog/2013/10/14/mapkit-and-esri-shapefiles
shapelib: http://shapelib.maptools.org
dala: http://www.geoportalpraha.cz

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)

IMG_0021

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