HERE Android SDK Developer's Guide

Venue Routing

The HERE Android SDK extends its 3D venue maps functionality to provide indoor routing. The SDK supports the following use cases:

  • Routing from store A to store B within a venue
  • Routing from an outside point to a point in a venue
  • Routing from a point in a venue to an outside point
  • Routing from a venue to another venue, with endpoints being a store or a point in a venue

Both on-line and off-line routing are supported. The classes that support this feature can be found in the com.here.android.mpa.venues3d and com.here.android.mpa.routing packages.

Note that if HERE has no routing information for an area between the outdoor part of the route and the venue entry point, the route visualization represents the unknown section of the route with a dotted line.

Routing Between Locations in a Venue

This section demonstrates how to calculate and display an indoor route by using a code example. The example is based on a scenario where a device user wants to find out how to reach another location in the same venue. In real life, the user would select the starting point and destination for the route by tapping on the map of the venue. However, for the sake of simplicity, the code below calculates a route by assuming the spaces are already selected.

Note: See the Getting Indoor Location Based on a Tap Point section for a code example of how to handle tap events to get a location for indoor venue routes.

The code below shows the implementation and is assumed to be part of an application. Previous initialization steps are assumed.

// Add the application as a listener for route-calculation-completed:
m_venueMapFragment.getRoutingController().addListener(m_activity);

// Route start and end set-up – they are spaces in a user-selected 3D venue.

// Set route start. You can choose an item from all spaces associated with the venue, or
// allow the application user to select an item and then use the callback onSpaceSelected().
SpaceLocation startLocation = new SpaceLocation(startSpace,
      m_venueMapFragment.getVenueController(venue));

// Set route end.
SpaceLocation endLocation = new SpaceLocation(endSpace,
      m_venueMapFragment.getVenueController(venue));

// Get route option objects
VenueRouteOptions venueRouteOptions = new VenueRouteOptions();
RouteOptions options = venueRouteOptions.getRouteOptions();

// Set route type, transport mode, number of routes to calculate:
options.setRouteType(Type.values()[m_routingOptionType.getSelectedItemPosition()]);
options.setTransportMode(
  TransportMode.values()[m_routingOptionMode.getSelectedItemPosition()]);
options.setRouteCount(1);

// Set route options:
venueRouteOptions.setRouteOptions(options);

// Calculate route - this is an asynchronous call, once the calculation is done
// onCombinedRouteCompleted() is called – see below.
routingController.calculateCombinedRoute(startLocation, endLocation,
  venueRouteOptions);

//...

// Callback invoked when the route calculation is done to display the route passed
// to it as an argument.
public void onCombinedRouteCompleted(CombinedRoute route) {
  // Use RoutingController to show route:
  m_venueMapFragment.getRoutingController().showRoute(route);

Routing Between Venues

You can perform routing between venues by using separate VenueController objects. For example, in the following, two different venues are used to retrieve VenueController objects:


// In this example m_startVenue and m_endVenue are assumed to be initialized
// with proper references.
SpaceLocation startLocation = new SpaceLocation(startSpace,
      m_venueMapFragment.getVenueController(m_startVenue));
SpaceLocation endLocation = new SpaceLocation(endSpace,
      m_venueMapFragment.getVenueController(m_endVenue));
}
// Other parts like in the previous example

Routing Using an Arbitrary Indoor Location

It is also possible to use an arbitrary indoor location that is not at a store or designated space as a route endpoint. An example of this kind of location is a point in a corridor. The next code snippet demonstrates the initialization of such an endpoint.


// Create a free point location to be used as a start location
// Here we assume that both current level and geo position is available in
// m_currentPosition. This can be obtained from, for example, some indoor positioning service.
LevelLocation startLocation = new LevelLocation(m_currentPosition.getLevel(),
  m_currentPosition.getGeoCoordinate(),
  m_venueMapFragment.getVenueController(venue));

The LevelLocation class extends BaseLocation and can be used as start or end location in calculateCombinedRoute() method of RoutingController, similar to SpaceLocation and OutdoorLocation.

The next example demonstrates route calculation from an indoor location, using type LevelLocation, to some location outside the venue, represented by an OutdoorLocation class.

// Create a free point location to be used as a start location
// Here we assume that both current level and geo position is available in
// m_currentPosition. This could be obtained from some indoor positioning
// service (not covered in this section).
LevelLocation startLocation = new LevelLocation(m_currentPosition.getLevel(),
  m_currentPosition.getGeoCoordinate(),
  m_venueMapFragment.getVenueController(venue));

// Create an outdoor location.
GeoCoordinate endPosition = new GeoCoordinate(52.517072, 13.411232);
OutdoorLocation endLocation = new OutdoorLocation(endPosition);

// Get route options objects
VenueRouteOptions venueRouteOptions = new VenueRouteOptions();
RouteOptions options = venueRouteOptions.getRouteOptions();

// Set route type, transport mode, number of routes to calculate:
options.setRouteType(Type.FASTEST);
options.setTransportMode(TransportMode.CAR);
options.setRouteCount(1);

// Set route options:
venueRouteOptions.setRouteOptions(options);

// Calculate route - this is an asynchronous call, once the calculation is done
// onCombinedRouteCompleted() is called – see below.
routingController.calculateCombinedRoute(startLocation, endLocation,
  venueRouteOptions);

//...

// Callback invoked when the route calculation is done to display the route passed
// to it as an argument.
public void onCombinedRouteCompleted(CombinedRoute route) {
  // Use RoutingController to show route:
  m_venueMapFragment.getRoutingController().showRoute(route);
}

Venue Route Options

VenueRouteOptions encapsulate options used in indoor routing. It is possible to set many parameters related to visualization of the route line (for example color, line width, visibility of start and end flags) as well as parameters related to how the route is calculated (for example if elevators are allowed, if stairs are allowed, if corridors are preferred). The next example shows route calculation from one level to another level while avoiding stairs. Initialization steps for used variables are assumed.

// set up start and end locations, assuming they're on different levels

// ...

// Set venue route options, including flag to avoid stairs:
VenueRouteOptions venueRouteOptions = new VenueRouteOptions();
venueRouteOptions.setStairsAllowed(false);
venueRouteOptions.setCorridorsPreferred(true);

// Set other route options
RouteOptions options = venueRouteOptions.getRouteOptions();
options.setRouteType(Type.SHORTEST);
options.setTransportMode(TransportMode.PEDESTRIAN);
options.setRouteCount(1);
venueRouteOptions.setRouteOptions(options);

// Calculate route - this is an asynchronous call, once the calculation is done
// onCombinedRouteCompleted() is called
routingController.calculateCombinedRoute(startLocation, endLocation,
  venueRouteOptions);

//...

Getting Indoor Location Based on a Tap Point

The next code example shows how to add a route point to an indoor route using the onTapEvent(PointF point) method of com.here.android.mpa.mapping.MapGesture.OnGestureListener.

public boolean onTapEvent(PointF point) {
 
  // convert tap point to GeoGoordinate
  Map map = m_venueLayer.getMap();
    GeoCoordinate tapPoint = map.pixelToGeo(point);
    if (tapPoint == null || !tapPoint.isValid()) {
        return false;
    }
 
  // If any venue is selected, get related VenueController
    Venue venue = m_venueLayer.getSelectedVenue();
    VenueController venueController = null;
    if (venue != null) {
        venueController = m_venueLayer.getVenueController(venue);
    }
 
  // If no venue was selected, consider tapped location as OutdoorLocation
  // and add it as route point.
    if (venueController == null) {
        BaseLocation location = new OutdoorLocation(tapPoint);
        addRoutePoint(location);
        return false;
    }
 
  // Otherwise consider tapped location as SpaceLocation and add it as route point.
    BaseLocation location = venueController.getLocation(point, m_preferSpaceSelection);
        addRoutePoint(location);
 
        return false;
    }
 
    private void addRoutePoint(BaseLocation location) {
           //Logic for saving route points.
    }
}

Calculating Route Length

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

@Override
public void onCombinedRouteCompleted(CombinedRoute combinedRoute) {

  double distance = 0.0;
  final List<IRouteSection> routeSections = route.getRouteSections();
  for (IRouteSection section : routeSections) {
    switch (section.getRouteSectionType()) {
      case VENUE:
        List<VenueManeuver> maneuvers = ((VenueRoute)section).getVenueManeuvers();
        distance += maneuvers.get(maneuvers.size() - 1).getDistanceFromStart();
        break;
      case LINK:
        GeoCoordinate from = ((LinkingRoute)section).getFrom();
        GeoCoordinate to = ((LinkingRoute)section).getTo();
        distance += from.distanceTo(from);
        break;
      case OUTDOOR:
        com.here.android.mpa.routing.Route route = ((OutdoorRoute)section).getRoute();
        distance += route.getLength();
        break;
      default:
        break;
      }
    }
  }
  // do something with distance information
};

Natural Guidance for Venue Maneuvers

Venue maneuvers provide the names of the closest POIs for natural guidance purposes. For each maneuver, this is the closest POI within a natural guidance radius around the position of the maneuver. If no POI exists within this radius, an empty string is returned. The natural guidance radius is a global parameter common to all maneuvers that may be set and queried by the user.

Note: For more information about natural guidance, see Turn-by-Turn Navigation for Walking and Driving.
VenueManeuver.setNaturalGuidanceRadius(10.0);
floar naturalGuidanceRadius = VenueManeuver.getNaturalGuidanceRadius();
String naturalGuidance = myManeuver.getNaturalGuidancePOI();

Bounding Boxes for Parts of Venue Routes

Venue and outdoor route sections provide axis-aligned bounding boxes for the route. Axis-aligned bounding boxes are provided for individual route segments for each level. These methods return null if a route has no segment on the given level.

GeoBoundingBox obb = outdoorRoute.getBoundingBox();
GeoBoundingBox vbb = venueRoute.getBoundingBox();
GeoBoundingBox lbb = venueRoute.getBoundingBox(level);

The bounding box for the venue route (vbb in the example) also provides altitude information that may be extracted using the getTopLeftFront() and getBottomRightBack() methods of GeoBoundingBox.