Venue Routing
SDK for Android 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 online and offline routing is supported. The classes that support this feature can be found in 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.
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 are 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));
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 LevelLocation
type 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 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
};
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 segments 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 getTopLeftFront()
and getBottomRightBack()
methods of GeoBoundingBox
.