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)

 

Advertisements

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

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

HxGN13: SG&I Perspectives LIVE

Here is a project I have been working on iKatastr2 (SpatialReader) with myVR technology showing terrain model with overlays of OGC WMS services. All from freely available data. Presented at HxGN live 2013

at 39:10 watch myVR multiplatform rendering technology integrated in the mobile app for 3D map visualisation.

Here are also few pictures form HxGN live booth/keynote

WMS overlay in iOS MapKit

update May 2014: iOS7 version and notes available here: https://blog.sumbera.com/2014/05/17/wms-on-mapkit-with-ios7/

 

I have crafted really simple and quick code at ESA App dev camp for viewing WMS sources.  And as few people questioned  me on  how to do this, I am posting the full code of the MapView component that takes sample WMS service (Ozone) and overlays this above MapKit.

In github here : https://github.com/Sumbera/WMSoverMapKit

you will find MapViewController that accepts  WMS  sources stored as array with BBOX %f, %f, %f, %f

-(void) addWMSOverlays: (NSArray*) overlays

this can be called from your rootController:

MapViewController * mapViewController = [[MapViewController alloc] init];

WMSOverlay * wmsOverlay =[[WMSOverlay alloc]
 initWithName:@"Ozone" Url:@"http://wdc.dlr.de/ogc/produkt_t?LAYERS=GOME2_O3&
 TRANSPARENT=TRUE&
 FORMAT=image/png&
 STYLES=&
 SLD=http%3A%2F%2Fwdc.dlr.de%2Fsld%2FGOME2_O3_sld.xml&
 TIME=2012-02-12T00:00:00Z&
 SERVICE=WMS&
 VERSION=1.1.1&
 REQUEST=GetMap&
 SRS=EPSG:4326&
 WIDTH=256&
 HEIGHT=256" 
 Opacity:0.5];
  [mapViewController  addWMSOverlays:[NSArray arrayWithObjects:wmsOverlay, nil]];

please note:

#1. that sample code uses experimentaly MKNetworkKit, which has some occasional troubles. You can replace the download method in WMSOverlayView  class downloadTile

#2 it uses simple hash for storing tiles on cache.

enjoy

How to erase iOS6 maps in MapKit

Update: be aware as this is not working on iOS7, however in iOS7 MapKit officially supports to disable base layer !

This blog : https://blog.sumbera.com/2011/09/18/how-to-disable-base-google-maps-in-mapkit/ wrote about how to disable Google maps in MapKit. Now with new iOS6 and brand new Apple maps and OpenGL rendering , the question is how to disable rendering of the base maps without using undocumented functions. Removing whole base layer (VKMapView) is possible but cripples touch handling of the overlays. So here is very simple way how to do this without removing VKMapView – just set opacity of the layer to 0.0. This will erase base iOS6 maps .

+(void) eraseiOS6maps:(UIView*) mapView{
   // -- get rendering layer
    UIView *rootView = [mapView.subviews objectAtIndex:0];
    UIView *vkmapView = [rootView.subviews objectAtIndex:0];
    UIView *vkmapCanvas = [vkmapView.subviews objectAtIndex:0];
   // -- set opacity to 0.0 
    [vkmapCanvas.layer setOpacity:0.0];
}

View hierarchy:

MkMapView/UIView/VKMapView/VKMapCanvas
MkMapView/UIView/MkScrollContainerView/MkOverlayContainerView/MkOverlayClusterView/<your overlay>
MkMapView/UIView/MkAnnotation/...
MkMapView/MkAttributionLabel

ikatastr2 on AppStore

I have just release iKatastr2 app on AppStore (free) that  might be useful for you to look at as it uses WMS sources and  custom tile loading on top of google.

App does simple stuff – shows cadastral information by tapping on cadastral  map of the Czech Republic.

As all is driven by JSON configuration it is quite easy to render similar information from other sources.

http://itunes.apple.com/us/app/ikatastr2/id545292674?ls=1&mt=8

 

enjoy !