SDK for iOS 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.

Public Venues Deprecation: Venues of publicly accessible locations such as airports or shopping malls are no longer being maintained by HERE. If you are a venue owner and want HERE to continue to maintain and surface your venue in our offerings, or those of our partners, contact us at venues.support@here.com.

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 NMAVenue3dMapLayer class, which is retrieved by using venue3dMapLayer property in NMAMapView. To use 3D Venues without a map, use 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 start: method before beginning to use it. To ensure that the NMAVenue3dMapLayer has started and to receive venue-related events, implement the NMAVenue3dMapLayerDelegate.

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

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

Working with 3D Venue Models

Once an NMAVenue3dMapLayer is correctly initialized, 3D-enabled venues are visible on 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, venueMapLayer:didTapVenue:atPoint: method in NMAVenue3dMapLayerDelegate is called with an 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, venueMapLayer:didSelectVenue: callback of the NMAVenue3dMapLayerDelegate interface is called.

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

selectVenue: method opens the venue right away in a synchronous manner by taking a downloaded NMAVenue3dVenue object as a parameter. However, selectVenueWithVenueId: and selectVenueWithVenueId:spaceId: methods may involve downloading the venue from the backend, asynchronously, while the venue is selected and opened. You can get a notification when asynchronous loading is complete by listening for 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, e.g. during map panning, venueMapLayer:didShowVenue: of NMAVenue3dMapLayerDelegate is called. venueMapLayer:didHideVenue: callback is triggered when the center point leaves the triggering area.

Note that to get the notifications, you must first set 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 an NMAVenue3dController object by using controllerForVenue:venue: method, and then change the level value.

Note that you can enable animations for both venue selection and floor transitions by setting 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 sharedVenueService method and start the service using start method. To ensure NMAVenue3dService initialization has successfully completed, check the initialization result in 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

An NMAVenue3dVenue object consists of one or more NMAVenue3dLevel objects. The NMAVenue3dLevel objects represent physical levels of the venue. Each NMAVenue3dLevel object consists 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 consists of one or more NMAVenue3dSpace objects.

NMAVenue3dVenue, NMAVenue3dOuterArea and NMAVenue3dSpace objects can be interacted by the user through tapping. For an opened venue use venueMapLayer:didSelectVenue: callback in NMAVenue3dMapLayerDelegate. For a selected space use venueMapLayer:didSelectSpace:inVenue: callback. Selected spaces are highlighted with different colors 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 part of 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 appearance 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 for 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 an 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 an NMAVenue3dSpace or an NMAVenue3dOuterArea. Similarly, you can also get spaces in an NMAVenue3dOuterArea.

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

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