SDK for iOS Developer's Guide

3D Venues FAQ

Can I customize the venue color scheme and venue icon?

Yes. POI attributes can be customized using NMAVenue3dStyleSettings object.

There are two types of icons:
  • Icons displayed on the map for a space, point-space, or facility (SVG file format)
  • Icons displayed in native controls such as a search filter list (PNG file format)

Map icons can be customized in two ways, either by replacing the respective SVG asset files with customized ones, or by dynamically replacing it at runtime using NMAVenue3dStyleSettings object. See the following code snippet as an example on how to customize icon for a space.

if ([venue.uniqueId isEqual:@"DM_12468"]) {
    NSString *placeId = @"Lv16133Ds1286559";
    NMAVenue3dSpace* space = [venue spaceWithId:@"Lv26051Ds3186063"];
    if (space != nil) {
      NMAVenue3dController* controller = venueMapLayer.venueController;
      NMAVenue3dStyleSettings* newStyleSet = [[NMAVenue3dStyleSettings alloc] init];
      NSData* imageData = [[NSData alloc]
                 initWithContentsOfURL:[NSURL URLWithString:@"https://placeholdit.imgix.net/"
                            @"~text?txtsize=2&txt=T&w=5&h=5]];
      newStyleSet.labelImage = [NMAImage imageWithUIImage:[UIImage imageWithData:imageData]];
      [controller setStyleSettings:newStyleSet forSpace:space];
    }
  }
Note: Using a private HERE account, PNG icons that are displayed in native controls can also be customized by replacing the respective PNG icon files with customized ones. Note that there are 4 different sizes for each iOS resolution type. To make these customizations, see Service Support to contact us for more details .

Can logos be added for individual POIs, such as for a restaurant?

Yes. You can modify the icon for an individual space dynamically using NMAVenue3dStyleSettings object. For details see NMAVenue3dStyleSettings API Reference.

Is it possible to expose venue data, in a classified manner, for a single user?

Yes, you can create a private HERE account and expose a "customized" version of the venue to it. See Service Support to contact us for more details.

What fonts are supported by the Venues feature?

There is currently no support for fonts. Only the default font is supported.

Are there venue routing penalties for different types of connectors, such as elevators?

Penalties are applied when the route is calculated in "fastest" mode. For "shortest" mode connectors are considered only if the geometry has a significant distance.

How can I create a colored NMAMapMarker?

See the following code snippet or NMAMapMarker API Reference.

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;
  }
}

How do I select point-spaces (spaces without geometry) and calculate a route to such a position?

Take the tapped position and calculate the route from those coordinates. The following is an example of how to handle the map tap events to get a location for a route.

- (void)mapView:(NMAMapView *)mapView didReceiveTapAtLocation:(CGPoint)tapLocation
{
  NMAVenue3dController* controller = _venueMapLayer.venueController;
  NMAVenue3dBaseLocation* location;
  if (controller != nil) {
    location = [controller getLocationAtX:tapLocation.x Y:tapLocation.y WithSpacePrefered:YES];
    [self addToRoute:location];
  }
  else {
    NMAGeoCoordinates *coords = [mapView geoCoordinatesFromPoint:tapLocation];
    location = [NMAVenue3dOutdoorLocation outdoorLocationWithGeoCoordinates:coords];
  }
  [self addRoutePoint:location];
}

- (void)addRoutePoint:(NMAVenue3dBaseLocation *)location
{
  // Logic for saving route points
}

How do I calculate the length of a route?

  1. From NMAVenue3dCombinedRoute result object, get all the route sections. Route sections can be of three types: NMAVenue3dRouteSectionTypeVenue, NMAVenue3dRouteSectionTypeLink, or NMAVenue3dRouteSectionTypeOutdoor.
  2. For each route type you need to calculate its distance individually. See the following example on how to calculate length of different route types.
- (void)calculateDistanceFor:(NMAVenue3dCombinedRoute*) combinedRoute
{
  double distance = 0.0;
  NSArray* routeSections = [combinedRoute routeSections];
  for (NMAVenue3dRouteSection* section : routeSections) {
    if ([section isKindOfClass:[NMAVenue3dVenueRouteSection class]]) {
  // get length of indoor sections
      NSArray* maneuvers = ((NMAVenue3dVenueRouteSection*)section).routeManeuvers;
      NMAVenue3dRouteManeuver* maneuver = maneuvers.lastObject;
      distance += (double)maneuver.distanceFromStart;
    }
    else if ([section isKindOfClass:[NMAVenue3dLinkRouteSection class]]) {
  // get length of link sections
      NMAGeoCoordinates* from = ((NMAVenue3dLinkRouteSection*)section).from;
      NMAGeoCoordinates* to = ((NMAVenue3dLinkRouteSection*)section).to;
      distance += [from distanceTo:to];
    }
    else if ([section isKindOfClass:[NMAVenue3dOutdoorRouteSection class]]) {
  // get length of outdoor sections
      NMARoute* route = ((NMAVenue3dOutdoorRouteSection*)section).route;
      distance += (double)route.length;
      NSLog(@"--> +distance (outdoor): %f", distance);
    }
  }
}

How can my app automatically open a venue right after the app starts?

At app start make sure NMAVenue3dService is initialized and then select the desired venue using NMAVenue3dMapLayer as shown in the following example:

//...
  // on applicaton startup register the app to receive venue service events
  [service addListener:self];
//...

- (void)venueServiceDidInitialize:(NMAVenue3dService *)venueService withResult:(NMAVenue3dServiceInitializationStatus)result
{

  if (result == NMAVenue3dServiceInitializationStatusOnlineSuccess ||
    result == NMAVenue3dServiceInitializationStatusOfflineSuccess) {
    // if the venue service started ok, select the venue
    [_venueMapLayer selectVenueWithVenueId:@"DM_7171"];
}
//...

How can my app detect whether a route passes a specific type of space, such as a security gate?

To identify if a route passes a certain type or category of space, loop through the route sections and inspect if a maneuver contains a space in the expected category. For example, the following code snippet shows how to find the first venue maneuver with category 4, which represents a security gate.

- (BOOL)category:(NSString*)category isInvolvedInRoute:(NMAVenue3dCombinedRoute*)route
{
  NSArray* routeSections = [route routeSections];
  for (NMAVenue3dRouteSection* section : routeSections) {
    if ([section isKindOfClass:[NMAVenue3dVenueRouteSection class]]) {
      NSArray* maneuvers = ((NMAVenue3dVenueRouteSection*)section).routeManeuvers;
      for (NMAVenue3dRouteManeuver* maneuver : maneuvers) {
        if (maneuver.space != nil && maneuver.space.content != nil) {
          NMAVenue3dContent* content = maneuver.space.content;
          if ([content.placeCategoryId isEqual:category]) {
            return YES;
          }
        }
      }
    }
  }
  return NO;
}

We get the spaces and facilities by iterating through all the levels and accessing NMAVenue3dLevel.spacesAndFacilities property. Is it possible to also get the entrances?

This is the correct way to get a list with all the spaces and facilities. However, entrances (accessors) are not exposed as POIs at the moment.

Is there a way to only show the venue model without showing the map tiles beneath it?

At the moment a venue can only be shown on top of the map.

Is there a way to integrate 3D Venues with Apache Cordova?

We do not support a Cordova plug-in. Only native Android and iOS SDKs are supported.

How can I get a nearby POI based on a space and a radius?

This is not currently supported.

How can I get a nearby POI based on an indoor routing line?

This is not possible at the moment. This is planned for a future release.

How can I get a certain area around a venue model for offline mode?

Once a venue has been downloaded, it is cached and will be available later in offline mode. However, you need to be online and request the venue prior to this.

Can venue entrance markers be customized?

HERE SDK already marks entrances on the map and on the route with entrance icons. For private venues you can customize these icons. See Service Support to contact us for more details.

How do I pre-cache individual venues without user interaction?

You need to download venues using NMAVenue3dService.
  • venueWithId:
  • venuesAtGeoCoordinates:
  • venuesInGeoBoundingBox:
For more information see NMAVenue3dService API Reference.

How do I translate geo locations into indoor locations, expressed as latitude, longitude, and level, for a given functional call within HERE SDK?

You need to have the geo location which you want to map inside the venue, as well as the level on which you intend to place those coordinates. Thus, you can use NMAVenue3dLevelLocation to construct the indoor location.

- (void)mapView:(NMAMapView *)mapView didReceiveTapAtLocation:(CGPoint)tapLocation
{
  // convert tap point to NMAGeoGoordinate
  NMAGeoCoordinates *coords = [mapView geoCoordinatesFromPoint:tapLocation];

  // If any venue is selected, get related venue controller
  NMAVenue3dController* venueController = _venueMapLayer.venueController;

  // If no venue was selected, consider tapped location as outdoor location
  // and add it as route point
  if (venueController == nil) {
    NMAVenue3dOutdoorLocation *loc = [NMAVenue3dOutdoorLocation  outdoorLocationWithGeoCoordinates:coords];
  [self addToRoute:loc];
  return;
  }

  // Otherwise find location inside a venue and add it as route point
  else {
    NMAVenue3dBaseLocation* loc = [venueController getLocationAtX:tapLocation.x
                                   Y:tapLocation.y
                           WithSpacePrefered:true];
    if ([loc isValid] && ![loc isKindOfClass:[NMAVenue3dOutdoorLocation class]]) {
      [self addToRoute:loc];
    }
  }
}
-(void)addToRoute:(NMAVenue3dBaseLocation*) baseLocation
{
  // do something with the route
}

The following code example shows how the total length of a route can be calculated:

- (void)didCalculateRoute:(NMAVenue3dCombinedRoute *)combinedRoute
{
  double distance = 0.0;
  NSArray *routeSections = combinedRoute.routeSections;

  for (id routeSection in routeSections) {
    if ([routeSection class] == [NMAVenue3dVenueRouteSection class]) {
      NMAVenue3dVenueRouteSection *section = (NMAVenue3dVenueRouteSection *)routeSection;
      NSArray *maneuvers = section.routeManeuvers;
      NMAVenue3dRouteManeuver *lastManeuver = [maneuvers lastObject];
      distance += [lastManeuver distanceFromStart];
    } else if ([routeSection class] == [NMAVenue3dLinkRouteSection class]) {
      NMAVenue3dLinkRouteSection *section = (NMAVenue3dLinkRouteSection *)routeSection;
      NMAGeoCoordinates *start = section.from;
      NMAGeoCoordinates *destination = section.to;
      distance += [start distanceTo:destination];
    } else if ([routeSection class] == [NMAVenue3dOutdoorRouteSection class]) {
      NMAVenue3dOutdoorRouteSection *section = (NMAVenue3dOutdoorRouteSection *)routeSection;
      NMARoute *route = section.route;
      distance += route.length;
    }
  }
  // do something with distance information
}