Using the new floor and indoor lock APIs


The old way (SDK versions < 2.9)


In our previous SDK versions prior to 2.9, you would use the location property of IALocationManager to either set your location explicitly, lock position to specific floor, give hints about the floor number or lock position to specific venue.


There are three main uses for setting location property manually:


1. Setting your location explicitly to specific latitude & longitude in specific floor


Objective C
IALocationManager *manager = [IALocationManager sharedInstance];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:60.01 longitude:24.123];
IALocation *iaLoc = [IALocation locationWithCLLocation:loc];
[iaLoc setFloor:[IAFloor floorWithLevel:3]];
manager.location = iaLoc;


    Here we initialize the position to latitude 60.01, longitude 24.123 and floor number 3.


2. Forcing positioning to specific floor plan id (a.k.a. explict floor plan or explicit region with floor plan id). This is flagged as deprecated in SDK 2.9 and will be removed in SDK 3.0 (see below)


Objective C
manager.location = [IALocation locationWithFloorPlanId:@"floorPlanId"];


    Here we force the positioning to specific floor plan of id "floorPlanId". Positioning will be locked to this floor plan until either next floorplan id is provided through the setLocation or positioning is stopped.


3. Forcing positioning to specific venue id (a.k.a. explicit venue or explicit region with venue id). This is flagged as deprecated in SDK 2.9 and will be removed in SDK 3.0 (see below)


Objective C
manager.location = [IALocation locationWithVenueId:@"locationId"];


    Here we force the positioning to specific venue of id "locationId". Positioning will be locked to this venue until either next venue or floor plan id is provided through the setLocation or positioning is stopped.


The new way (SDK versions >= 2.9)


In the new SDK 2.9, we have added new APIs for locking the positioning to new specific floor and / or building.


1. Setting your location explicitly to specific latitude & longitude can be done via location property like in older SDK versions.


2. Forcing positioning to specific floor plan id is replaced by locking positioning to specific floor number. Locking positioning can be done by using the new lockFloor method in IALocationManager. In addition to locking, new method unlockFloor is provided so positioning can be unlocked from the specific floor.


// Lock position to floor number 3
IALocationManager *manager = [IALocationManager sharedInstance];
[manager lockFloor:3];

// Unlock positioning so floor level is detected automatically
[manager unlockFloor];



3. Forcing positioning to specific venue id is replaced by locking positioning to indoors. Correct venue is detected automatically. Locking indoors can be achieved by new lockIndoors method which locks the positioning inside the venue. This also means that GPS is no longer scanned. lockIndoors needs to be called with a boolean argument indicating whether you want to lock or unlock to indoor positioning.


Objective C
// Lock positioning indoors (i.e., enable indoor-only mode)
IALocationManager *manager = [IALocationManager sharedInstance];
[manager lockIndoors:true];

// Unlock positioning indoors (disable indoor-only mode)
[manager lockIndoors:false];


The new APIs lockFloor and lockIndoors can be used together but it is redundant in most cases: Locking positioning to specific floor also implicitly locks positioning indoors.


Why to migrate


The new lockFloor and lockIndoors methods provide cleaner solution to manipulating where the positioning happens. You no longer need to use any UUIDs to set the positioning to specific floor plan or venue id. This in turn results to much cleaner application level logic if specific floor positioning is required. 


The new APIs also provide unlock methods which were previously missing. SDK 2.9 also supports the old IALocationManager's location property approach, but its functionality will be removed in SDK 3.0.


No more manual metadata fetching for regions


The old way (SDK versions < 2.9)


In our older SDK versions you would use IAResourceManager to fetch the meta data of floor plans, e.g. the bitmap image or pixel to WGS transformations.

For example, if you wanted to fetch the bitmap image of the specific floor plan by id, you would have had to implement something similar to the following:


1. Implement IALocationManagerDelegate and fetch the metadata from IndoorAtlas servers using the IAResourceManager. The information is stored in IARegion

@interface ExampleViewController () <IALocationManagerDelegate,  ...> {
     id<IAFetchTask> floorPlanFetch;
     id<IAFetchTask> imageFetch;
    // ...
}
@property (nonatomic, strong) IAResourceManager *resourceManager;
@property (strong) IAFloorPlan *floorPlan;

// ...

- (void)indoorLocationManager:(IALocationManager *)manager didEnterRegion:(IARegion *)region
{
    if (region.type != kIARegionTypeFloorPlan)
        return;

     if (floorPlanFetch != nil) {
         [floorPlanFetch cancel];
         floorPlanFetch = nil;
     }
    __weak typeof(self) weakSelf = self;
    floorPlanFetch = [self.resourceManager fetchFloorPlanWithId:region.identifier andCompletion:^(IAFloorPlan *floorPlan, NSError *error) {
        if (!error) {
            self.floorPlan = floorPlan;
            [weakSelf fetchImage:floorPlan];
         }
    }];
}


2. Read the URL of the bitmap that is stored in IndoorAtlas servers using imageUrl property of the IAFloorPlan.


- (void)fetchImage:(IAFloorPlan *)floorPlan
{
    if (imageFetch != nil) {
        [imageFetch cancel];
        imageFetch = nil;
    }
    __weak typeof(self) weakSelf = self;
    imageFetch = [self.resourceManager fetchFloorPlanImageWithUrl:floorPlan.imageUrl andCompletion:^(NSData *imageData, NSError *error){
        if (!error) {
            fpImage = [[UIImage alloc] initWithData:imageData];
        }
    }];
}





The new way (SDK versions >= 2.9)


WARNING: The new floor plan and venue properties described below are not available (will return null) if the old explicit location API is used with explicit region ids. (explicit floor plans, 2., or venues, 3.). If the old explicit location API is used, metadata needs to be fetched the old way. This does not concern setting location with locations (1.). Moral of the story: do not use explicit region IDs anymore.


In our new SDK versions, starting from version 2.9.0, the metadata information is provided in the IARegion ready for use. This means that the application level logic does not need to handle the explicit metadata downloading using the IAResourceManager.


Starting from 2.9.0, IARegion class has two new properties relating to the new functionality: floorplan and venue. The new properties will return the metadata relating to either the floor plan or venue, depending which one the IARegion corresponds to (as previously, type can be checked with type property). We have also added new class IAVenue which represents the metadata for venue.


With the new APIs, the previous example simplifies to the following:


1. Implement the didEnterRegion listener


Objective C
- (void)indoorLocationManager:(IALocationManager *)manager didEnterRegion:(IARegion *)region
{
    if (region.type != kIARegionTypeFloorPlan)
        return;

    [self fetchImage:region.floorplan];
}


2. Fetch the image bitmap 


Objective C
- (void)fetchImage:(IAFloorPlan *)floorPlan
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                   ^{
                       NSData *imageData = [NSData dataWithContentsOfURL:[floorPlan imageUrl]];
                       dispatch_sync(dispatch_get_main_queue(), ^{
                           fpImage = [UIImage imageWithData:imageData];
                       });
                   });
}


Wayfinding


The old way (Wayfinding plugin beta versions 2.7 and 2.8)


In the wayfinding plugin, one would initialize an IndoorAtlas wayfinder (IAWayfinding) using a wayfinding graph, which has been manually downloaded from the IndoorAtlas web app, together with the application context:


// Load a JSON graph string, obtained from the web tool, to wayfinding
// component 
IAWayfinding *wayfinder = [[IAWayfinding alloc] initWithGraph:graphString];


Then to start routing an user to a given destination, the destination was first set in the wayfinder


// Set the latitude, longitude and floor number
[wayfinder setDestinationWithLatitude:60.1684003 Longitude:24.9306895 Floor:1];


and finally the route from the current location to destination is was obtained by first providing the user’s location and then calling getRoute:


// Set the latitude, longitude and floor number
[wayfinder setLocationWithLatitude:60.1696597 Longitude:24.932497 Floor:1];
NSArray *route = [NSArray array];
route = [wayfinder getRoute];



The new way (SDK 2.9+)


See the new iOS Map View sample code with wayfinding to see how this works in a complete application. Note: The new integrated wayfinding is not yet available in mainland China.


In the new SDK, the wayfinding graph does not need to be manually downloaded. Instead the wayfinding graphs are automatically handled by the SDK. The wayfinding API is also integrated into the SDK instead of being in a separate plugin. The new integrated API works as follows. First, one defines an didUpdateRoute

- (void)indoorLocationManager:(IALocationManager *)manager didUpdateRoute:(IARoute *)route {
    // visualize route
}


then wayfinding is started by providing the destination as an IAWayfindingRequest

IAWayfindingRequest *req = [[IAWayfindingRequest alloc] init];
req.coordinate = CLLocationCoordinate2DMake(60.1696597, 24.932497);
req.floor = 1;
[self.locationManager startMonitoringForWayfinding:req];


didUpdateRoute starts receiving updates as soon as the wayfinding graph has been downloaded (or loaded from the automatic disk cache). The route is updated on each new IndoorAtlas location and it always connects the latest IALocation and the destination set in IAWayfindingRequest. If routing between these two locations is impossible, for instance, the floor the user is on has no wayfinding graph or the wayfinding graph is disconnected, the returned list of routing legs is empty.


The returned IARoute object consists of IARouteLegs (which used to be called IARoutingLeg in the old wayfinding plugin). Each leg has begin and end IARoutePoints (which used to be called IARoutingPoints in the old plugin). Unlike the wayfinding plugin, the SDK has automatic rerouting logic, which avoids unnecessary re-routing and tries to primarily route the user to the destination along the original (first returned) route. 


When the user has reached the destination or, for example, wants to cancel the wayfinding session, IndoorAtlas wayfinding can be stopped by calling IALocationManager.stopMonitoringForWayfinding

[self.locationManager stopMonitoringForWayfinding];

See the iOS sample code for one method of checking if the user has reached the destination using the returned route.