Truck Profile¶
In this guide you will learn how to compute a
route based on the accessibility given by the
physical characteristics of a truck,
such as height, weight, length, width
and number of axles, and then render the route
on the map.
Setup¶
First, get an API key token, see the
Getting Started guide.
Download the TruckProfile project
archive file or clone the project with Git
See the Configure Android Example guide.
Run the example¶
In Android Studio, from the File
menu, select Sync Project with Gradle Files
An android device should be connected via USB cable.
Press SHIFT+F10 to compile, install and run the example on the
android device.
How it works¶
You can open the MainActivity.kt file to see how the truck
route is computed and rendered on the map based on the
accessibility given by the physical characteristics of the truck.
1private val routingService = RoutingService(
2 onStarted = {
3 progressBar.visibility = View.VISIBLE
4 },
5 onCompleted = { routes, errorCode, _ ->
6 progressBar.visibility = View.GONE
7 when (errorCode)
8 {
9 GemError.NoError ->
10 {
11 routesList = routes
12 SdkCall.execute { gemSurfaceView.mapView?.presentRoutes(
13 routes = routes,
14 displayBubble = true
15 )
16 }
17 settingsButtons.visibility = View.VISIBLE
18 }
19 GemError.Cancel ->
20 {
21 showDialog("The routing action was canceled.")
22 }
23 else ->
24 {
25 // There was a problem at computing the routing operation.
26 showDialog("Routing service error: ${GemError.getMessage(errorCode)}")
27 }
28 }
29 }
30)
A routing service is instantiated to compute and render the truck route.
The
onStarted
and onCompleted
routing callbacks are overridden and
implemented, to show, and then hide, respectively, the routing computation
progress bar, which is useful for very slow devices, where the route
computation may take long enough to be noticeable by the user.When the route calculation is completed, if there is no error, the resulting
routes (as there could be more than one alternate route in the resulting set
between the specified departure and destination points)
are drawn on the map:
gemSurfaceView.mapView?.presentRoutes()
Then the settings button is set to visible, so that the user can
introduce the physical characteristics of the truck. Upon saving these,
the route is computed again, in case it has to change to accomodate
the updated characteristics of the truck, such as its dimensions and weight.
1override fun onCreate(savedInstanceState: Bundle?)
2{
3 super.onCreate(savedInstanceState)
4 setContentView(R.layout.activity_main)
5 gemSurfaceView = findViewById(R.id.gem_surface_view)
6 progressBar = findViewById(R.id.progress_bar)
7 settingsButtons = findViewById<FloatingActionButton?>(R.id.settings_button).also {
8 it.setOnClickListener {
9 onSettingsButtonClicked()
10 }
11 }
12 SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
13 if (!isReady) return@onMapDataReady
14 // Defines an action that should be done when the world map is ready (Updated/ loaded).
15 SdkCall.execute {
16 waypoints = arrayListOf(
17 Landmark("London", 51.5073204, -0.1276475),
18 Landmark("Paris", 48.8566932, 2.3514616)
19 )
20 routingService.calculateRoute(waypoints)
21 }
22 gemSurfaceView.mapView?.onTouch = { xy ->
23 SdkCall.execute {
24 // tell the map view where the touch event happened
25 gemSurfaceView.mapView?.cursorScreenPosition = xy
26 // get the visible routes at the touch event point
27 val routes = gemSurfaceView.mapView?.cursorSelectionRoutes
28 // check if there is any route
29 if (!routes.isNullOrEmpty())
30 {
31 // set the touched route as the main route and center on it
32 val route = routes[0]
33 gemSurfaceView.mapView?.apply {
34 preferences?.routes?.mainRoute = route
35 centerOnRoutes(routesList)
36 }
37 }
38 }
39 }
40 }
41 SdkSettings.onApiTokenRejected = {
42 showDialog("TOKEN REJECTED")
43 }
44 if (!Util.isInternetConnected(this))
45 {
46 showDialog("You must be connected to the internet!")
47 }
48}
The
onCreate()
function is overridden in the
MainActivity: AppCompatActivity()
class, and checks if
internet access is available, showing a dialog message if not.findViewById()
is used to obtain pointers to the various
graphical user interface elements where text or graphical data
is to be displayed.A click listener is set for the settings button, to recompute
the route when the user changes the physical parameters of the truck.
it.setOnClickListener { onSettingsButtonClicked() }
When the map is loaded and ready,
onMapDataReady@{}
the routing service instantiated and shown above is used to
calculate the route between a list of 2 predefined waypoints
where the first is the departure point and the second is
the destination point:
routingService.calculateRoute(waypoints)
Each waypoint is a
Landmark
containing a name, a latitude,
in degrees, and a longitude, in degrees:Landmark("Paris", 48.8566932, 2.3514616)
The list of waypoints from which a route is calculated must
have at least 2 elements, for the departure and destination,
respectively, but can have more elements, for additional
waypoints along the route. In this example there are 2
waypoints in the list.
A touch listener is defined
gemSurfaceView.mapView?.onTouch = { xy ->
and
gemSurfaceView.mapView?.cursorSelectionRoutes
is used to see if the user touched one or more routes on
the map. If so, the first touched route (at index 0) is
selected and set as the main route, which causes it to
be drawn in dark blue on the map.Then the camera centers on the bounding box containing
all routes between the departure and destination points.
centerOnRoutes(routesList)
1private val adapter = TruckProfileSettingsAdapter(getInitialDataSet())
A variable in the
class MainActivity : AppCompatActivity()
is
created to hold the truck dimensions and other attributes.1private fun getInitialDataSet(): List<TruckProfileSettingsModel>
The
getInitialDataSet()
function sets the default initial
values in the form with the truck dimensions and other attributes
required for identifying a corresponding route between the
given departure and destination which is navigable by the
specified truck. 1private fun onSettingsButtonClicked()
2{
3 val builder = AlertDialog.Builder(this)
4 val convertView = layoutInflater.inflate(R.layout.truck_profile_settings_view, null)
5 val listView = convertView.findViewById<RecyclerView>(R.id.truck_profile_settings_list).apply
6 {
7 layoutManager = LinearLayoutManager(this@MainActivity)
8 addItemDecoration(DividerItemDecoration(applicationContext,
9 (layoutManager as LinearLayoutManager).orientation))
10 }
11 listView.adapter = adapter
12 builder.setTitle(getString(R.string.app_name))
13 builder.setView(convertView)
14 builder.setNeutralButton(getString(R.string.save)) { dialog, _ ->
15 onSaveButtonClicked()
16 dialog.dismiss()
17 }
18 val dialog = builder.create()
19 dialog.show()
20}
The
onSettingsButtonClicked()
function is called by the
listener defined in the onCreate()
function above, when
the user clicks the industrial wheel settings button to
modify the truck profile attributes.This function uses the adapter variable defined above to
display the truck attribute values and enable the user to
modify them, so they can then be used to find a route
appropriate for the truck.
A save button is defined, which closes the dialog and calls
the
onSaveButtonClicked()
function to calculate the route
using the updated truck parameter values. 1private fun onSaveButtonClicked()
2{
3 val dataSet = adapter.dataSet
4 // convert m to cm
5 val width = (dataSet[ETruckProfileSettings.Width.ordinal].currentDoubleValue * 100).toInt()
6 val height = (dataSet[ETruckProfileSettings.Height.ordinal].currentDoubleValue * 100).toInt()
7 val length = (dataSet[ETruckProfileSettings.Length.ordinal].currentDoubleValue * 100).toInt()
8 // convert t to kg
9 val weight = (dataSet[ETruckProfileSettings.Weight.ordinal].currentDoubleValue * 1000).toInt()
10 val axleWeight = (dataSet[ETruckProfileSettings.AxleWeight.ordinal].currentDoubleValue * 1000).toInt()
11 // convert km/h to m/s
12 val maxSpeed = dataSet[ETruckProfileSettings.MaxSpeed.ordinal].currentIntValue * 0.27778
13 SdkCall.execute {
14 routingService.apply {
15 preferences.alternativesSchema = ERouteAlternativesSchema.Never
16 preferences.transportMode = ERouteTransportMode.Lorry
17 preferences.truckProfile = TruckProfile(
18 massKg = weight,
19 heightCm = height,
20 lengthCm = length,
21 widthCm = width,
22 axleLoadKg = axleWeight,
23 maxSpeedMs = maxSpeed
24 )
25 calculateRoute(waypoints)
26 }
27 }
28}
The
onSaveButtonClicked()
function sets the truck profile
attributes in the preferences and then calculates the route usingcalculateRoute(waypoints)