HERE iOS SDK Developer's Guide

3D Venues FAQ

Can I customize the venue color scheme and venue icon?

Yes. POI attributes can be customized using the 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 the 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, contact a HERE representative.

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

Yes. You can modify the icon for an individual space dynamically using the NMAVenue3dStyleSettings object. For details, see the 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. Please contact a HERE representative for more information.

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 the 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 the 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 the NMAVenue3dService is initialized and then select the desired venue using NMAVenue3dMapLayer, as shown in the following example:

//...
  // in 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 the 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.

Can airport venues be identified by their IATA airport codes?

This can only be done by searching through the core map POI database (for example, using HERE WeGo app) for the IATA code. For example, you may search for "fra", "Fra", or "FRA" and get the POI result "Frankfurt Airport (FRA)". By doing this, the venue map model's footprint (DM_9964 - "Frankfurt International Airport") becomes exposed on the map as an unopened model within the map bounding box.

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 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, these icons can be customized by contacting HERE representatives.

How do I pre-cache known airports without user interaction?

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

How do I translate geo-locations into indoor locations, expressed as latitude, longitude, and level, for a given functional call within the 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
}

Calculating Route Length

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
}

You cannot use this account to purchase a commercial plan on Developer Portal, as it is already associated to plans with different payment methods.

To purchase a commercial plan on Developer Portal, please register for or sign in with a different HERE Account.

Something took longer than expected.

The project should be available soon under your projects page.

Sorry, our services are not available in this region.

Something seems to have gone wrong. Please try again later.

We've detected that your account is set to Australian Dollars (AUD).
Unfortunately, we do not offer checkouts in AUD anymore.
You can continue using your current plan as normal, but to subscribe to one of our new plans,
please register for a new HERE account or contact us for billing questions on selfservesupport@here.com.