HERE iOS SDK Developer's Guide

3D Venues

This section gives an overview of the classes and interfaces associated with the 3D Venues feature. Examples of available 3D venues include shopping malls and airports. Three feature use cases are explored: searching for a venue, opening a venue, and getting a notification when a venue is visible in the viewport.

The classes covered in this section include NMAVenue3dMapLayer, NMAVenue3dService, NMAVenue3dMapLayerDelegate, NMAVenue3dController, NMAVenue3dServiceListener

Figure 1. 3D venue map of a Berlin shopping center

The 3D Venues feature can be used with or without a map. To use it with a map, use the NMAVenue3dMapLayer class, which is retrieved by using the venue3dMapLayer property in NMAMapView. To use 3D Venues without a map, use the NMAVenue3dService class.

Initialization

NMAVenue3dMapLayer provides developers with access to all 3D venue-related features on a map. To begin using the layer, NMAVenue3dMapLayer needs to be retrieved from NMAMapView, for example:

_venueMapLayer = self.mapView.venue3dMapLayer;
Note: NMAVenue3dMapLayer must be retrieved from NMAMapView. You cannot directly instantiate it.

After retrieving the NMAVenue3dMapLayer, call the start: method before beginning to use it. To ensure that the NMAVenue3dMapLayer has started and to receive venue-related events and, implement the NMAVenue3dMapLayerDelegate.

- (void)venueMapLayerDidStart:(NMAVenue3dMapLayer *)venueMapLayer {
  // venue map layer is ready to be used
}

You can also retrieve the service status using the initializationStatus property in NMAVenue3dService.

Working with 3D Venue Models

Once a NMAVenue3dMapLayer is correctly initialized, 3D-enabled venues are visible in the map. These venues can be distinguished by their colors and icons, as in the screenshot below.

Figure 2. A 3D venue on the Map

NMAVenue3dMapLayer offers two ways to select a venue and open the indoor map view. When a user taps the venue, the venueMapLayer:didTapVenue:atPoint: method in NMAVenue3dMapLayerDelegate is called with a NMAVenue3dVenue object as a parameter. The venue can then be opened by giving the NMAVenue3dVenue object to selectVenue:. For example:


- (void)venueMapLayer:(NMAVenue3dMapLayer *)venueMapLayer didTapVenue:(NMAVenue3dVenue *)venue
  atPoint:(CGPoint)point
{
  _venue = venue;
  _tappedPosition = [self.mapView geoCoordinatesFromPoint:point];
  _tappedVenueId = [NSString stringWithString:_venue.uniqueId];
  [_venueMapLayer selectVenue:_venue];
}

When the venue is selected, the venueMapLayer:didSelectVenue: callback of the NMAVenue3dMapLayerDelegate interface is called.

A venue can also be selected and opened by giving its identifier by using the selectVenueWithVenueId: method in NMAVenue3dMapLayer. For example, a typical scenario is a venue search where a successful search results in an opened venue. You can also open a venue with a specific space selected by using the selectVenueWithVenueId:spaceId: method. This is suitable for searching specific space inside the venue.

The selectVenue: method opens the venue right away in a synchronous manner by taking a downloaded NMAVenue3dVenue object as a parameter. However, the selectVenueWithVenueId: and selectVenueWithVenueId:spaceId: methods may involve downloading the venue from the back-end, asynchronously, while the venue is selected and opened. You can get a notification for when asynchronous loading is complete by listening for the venueService:didGetVenue: callback in NMAVenue3dServiceListener.

It is also possible to receive a notification when there is a venue in the viewport. You can use this callback to implement a feature, such as drawing user attention to the venue when it is visible.

The triggering area for this is a rectangle at the center of the viewport. The width of the area is two-thirds of the screen width, and the height is equal to the width. When the center point of the venue enters this triggering area, such as during map panning, venueMapLayer:didShowVenue: of NMAVenue3dMapLayerDelegate is called. The venueMapLayer:didHideVenue: callback is triggered when the center point leaves the triggering area.

Note that to get the notifications, you must first set the shouldCheckVenuesInViewport property to YES, for example:

// enabling venue visible notification
_venueMapLayer.shouldCheckVenuesInViewport = YES;
//...
- (void)venueMapLayer:(NMAVenue3dMapLayer *)venueMapLayer
  didShowVenueWithController:(NMAVenue3dController *)controller
{
  // venue entered triggering area
}
Note: This feature does not cause much processing, as checking is performed only once when map movement stops. The notification is not sent during continuous movement, even when there is a venue in the triggering area.

To change the current floor for a given venue, retrieve a NMAVenue3dController object by using the controllerForVenue:venue: method, and then change the level value.

Note that you can enable animations for both venue selection and floor transitions by setting the animatesFloorChange and animatesVenueSelection to YES in the map layer.

The following example shows how to add an NMAMapMarker to a space upon a didSelectSpace event, and how to remove it when the space is deselected.

NMAMapMarker *_marker;

- (void)venueMapLayer:(NMAVenue3dMapLayer *)venueMapLayer
       didSelectSpace:(NMAVenue3dSpace *)space
              inVenue:(NMAVenue3dVenue *)venue
{
    [self removeMarker];
    UIImage *image = [UIImage imageNamed:@"markerIcon"];
    NMAImage *icon = [NMAImage imageWithUIImage:image];
    _marker = [NMAMapMarker mapMarkerWithGeoCoordinates:space.geoCenter icon:icon];
    [_marker setAnchorOffsetUsingLayoutPosition:NMALayoutPositionBottomCenter];
    _marker.mapLayerType = NMAMapLayerTypeForeground;
    _marker.zIndex = 100;
    [self.mainVC.activeMapView addMapObject:_marker];
}

- (void)venueMapLayer:(NMAVenue3dMapLayer *)venueMapLayer
     didDeselectSpace:(NMAVenue3dSpace *)space
              inVenue:(NMAVenue3dVenue *)venue
{
    [self removeMarker];
}

- (void)removeMarker
{
    if (_marker != nullptr) {
        [self.mainVC.activeMapView removeMapObject:_marker];
        _marker = nullptr;
    }
}

NMAVenue3dService

Venue Service and the venue features can be used without a map. To use the venue service, obtain an NMAVenue3dService instance by using the sharedVenueService method, and start the service using the start method. To ensure NMAVenue3dService initialization has successfully completed, check the initialization result in the venueServiceDidInitialize:withResult: callback method in NMAVenue3dServiceListener. For example:

- (void)venueServiceDidInitialize:(NMAVenue3dService *)venueService
    withResult:(NMAVenue3dServiceInitializationStatus)result
{
  // initialized
  if (result == NMAVenue3dServiceInitializationStatusOnlineSuccess) {
    // init ok
  } else if (result == NMAVenue3dServiceInitializationStatusOfflineSuccess) {
    // failed to authenticate, but cached content available
  } else {
    // something else has gone wrong
  }
}

- (void)venueService:(NMAVenue3dService *)venueService didGetVenue:(NMAVenue3dVenue *)venue
{
  //venue has been loaded
  _venue = venue;
}

NMAVenue3dService offers methods for searching and loading venues without using a map. For example, the code below retrieves the closest venue inside a given radius near a given location. The area can also be defined by NMAGeoBoundingBox rather than a radius.

- (void)loadClosestVenue
{
  NMAVenue3dService *venueService = [NMAVenue3dService sharedVenueService];
  NMAGeoCoordinates *myLocation = [NMAGeoCoordinates geoCoordinatesWithLatitude:60.43704
    longitude:22.212710];
  float radiusInMeters = 5000.0f;
  NMAVenue3dVenueInfo *closetVenueInfo = [venueService venueAtGeoCoordinates:myLocation
    radius:radiusInMeters];
  [venueService getVenueWithInfo:closetVenueInfo];
}

For more information, consult the API Reference. The NMAVenue3dService is also invoked when NMAVenue3dMapLayer is used, so it can be used in a similar manner.

Working with Venues

A NMAVenue3dVenue object consist of one or more NMAVenue3dLevel objects. The NMAVenue3dLevel objects represents physical levels of the venue. Each NMAVenue3dLevel object consist of one or more NMAVenue3dOuterArea objects. For example, a building with common ground level areas can contain two separate towers on top of that common area, and so there would be two NMAVenue3dOuterArea objects in higher levels in that venue. An NMAVenue3dOuterArea consist of one or more NMAVenue3dSpace objects.

NMAVenue3dVenue, NMAVenue3dOuterArea and NMAVenue3dSpace objects can be interacted by the user through tapping. For an opened venue, use the venueMapLayer:didSelectVenue: callback in NMAVenue3dMapLayerDelegate. For a selected space, use the callback venueMapLayer:didSelectSpace:inVenue:. Selected spaces are highlighted with different color in an opened venue.

Both NMAVenue3dVenue and NMAVenue3dSpace objects contain NMAVenue3dContent objects. NMAVenue3dContent encapsulates information related to the object, such as name, address, other contact information and category of the venue or space. There is also a concept of selected floor, which is the same as the visible floor. This is demonstrated in the following screenshot. Please note that the floor selection widget in this screenshot is not a part of the HERE SDK.

Figure 3. Selected Space

Open Mode

When open mode is enabled, venues that are in the viewport are opened automatically, rather than requiring the user to click on the venue to open it. The venue closest to the center of the screen is always selected.

Open mode can be enabled on NMAVenue3dMapLayer.

venueMapLayer.openMode = YES;
BOOL isOpenMode = venueMapLayer.openMode;

Dynamic Styles

NMAVenue3dStyleSettings encapsulates the parameters that have an impact on the visual appearances of opened venues. You can set space names, icons, and colors by using this object. The fill and outline colors can be also set separately to selected and unselected spaces.

The following example shows how to set the name, label, fill color, and outline color to the given NMAVenue3dSpace object. The code snippet does not contain completed code but assumes that variables have been initialized.

- (void)updateStylesFor:(NMAVenue3dSpace *)space
        inVenue:(NMAVenue3dVenue *)venue
{
  UIColor* selectedColor =
    [UIColor colorWithRed:1.0f green: 0.0f blue:0.0f alpha:1.0f];
  UIColor* unselectedColor =
    [UIColor colorWithRed:1.0f green: 1.0f blue:0.0f alpha:1.0f];
  UIColor* outlineColor =
    [UIColor colorWithRed:0.0f green: 0.0f blue:1.0f alpha:1.0f];

  NMAVenue3dController *controller = _venueMapLayer.venueController;
  NMAVenue3dStyleSettings *settings = [[NMAVenue3dStyleSettings alloc] init];

  settings.labelName = @"My Space";
  settings.labelImage = [NMAImage imageWithUIImage:[UIImage imageNamed:@"MyLabel.png"]];

  settings.selectedFillColor = selectedColor;
  settings.fillColor = unselectedColor;
  settings.outlineColor = outlineColor;

  [controller setStyleSettings:settings forSpace:space];
}

Nearby Spaces

You can find all spaces in a radius around a given position by using a NMAVenue3dLevel or an NMAVenue3dOuterArea object. The position needs to be given as a geocoordinate, and the radius in meters. The returned list of spaces contains all spaces that fall within or intersect the radius.

NMAGeoCoordinates *myLocation =
  [NMAGeoCoordinates geoCoordinatesWithLatitude:60.43704 longitude:22.212710];
NSArray nearbySpaces = [level nearbySpacesAroundPosition:myLocation withinRadius:10.0];

Area at Position

You can retrieve areas in a level by specifying a position. The area returned will either be a NMAVenue3dSpace or an NMAVenue3dOuterArea. Similarly, you can also get spaces in a NMAVenue3dOuterArea.

In case of nested spaces, the innermost nested space encompassing the position is be returned.

NMAGeoCoordinates *myLocation =
  [NMAGeoCoordinates geoCoordinatesWithLatitude:60.43704 longitude:22.212710];
NMAVenue3dArea *area = [level areaAtPosition:myLocation];
NMAVenue3dSpace *space = [outerArea spaceAtPosition:myLocation];