05 Route calculation
Overview
In this tutorial you will learn how to calculate a route from A to B and how to influence the routing by setting your vehicle parameters.
Base
You can use your results from Tutorial04
as a base for our new project.
Prerequisites
Please copy the following files from the Tutorial05 folder to your project directory:
- CalcRouteRunnable.cpp
- CalcRouteRunnable.h
- GPSPushLocationRunnable.cpp
- GPSPushLocationRunnable.h
- SDKJobQueue.cpp
- SDKJobQueue.h
Because we have too much (simple) changes in our MapWidget class that needn't be shown here, replace the files
- MapWidget.cpp
- MapWidget.h
also.
Add the new files to the CMakeLists.txt file:
set(Tutorial_SRCS ... SDKJobQueue.cpp CalcRouteRunnable.cpp GPSPushLocationRunnable.cpp ) set(Tutorial_HEADER ... SDKJobQueue.h CalcRouteRunnable.h GPSPushLocationRunnable.h )
Call cmake ../
in the build directory or build the ALL_BUILD project of the solution to update it.
Also, always trigger a rebuild after copying to ensure that replaced files will be newly built.
Calculating a route
Every long lasting operation should be performed in a background thread to avoid stalling the GUI thread and therefore the user interactions. So we put long lasting operations in a seperate thread. We add a little helper class that implements a simple worker thread queue, called the SDKJobQueue, where you can queue your long lasting NavigationSDK operations.
SDKJobQueue.cpp:
... SDKJobQueue::SDKJobQueue() { mThreadPool = new QThreadPool(); mThreadPool->setMaxThreadCount(1); } void SDKJobQueue::push(QRunnable * runnable) { mThreadPool->start(runnable); } void SDKJobQueue::waitForDone() { mThreadPool->waitForDone(); } ...
The queue uses the QThreadPool for queueing jobs. We set the maximum parallel threads to one, so we really queue the jobs. We have a function called push() which will add a QRunnable to the queue and a function waitForDone() which will wait until the current job has ended.
Hint
You can easily use your own asynchronous mechanism. But be aware that most of the NavigationSDK functions are currently mutual exclusive and cannot be called concurrently. So try to call only one NavigationSDK method at a time to avoid locks in your application.
To calculate a route, we create a QRunnable with all the route calculation operations and push it via SDKJobQueue::getInstance()->push()
to the SDKJobQueue.
The run() function implements all the code we need to calculate a route from our current position to our given destination.
So, let us take a look at the class CalculateRouteRunnable:
CalcRouteRunnable.cpp:
void CalcRouteRunnable::run() { SDK_Waypoint start; SDK_InitWaypoint(&start); SDK_GPSData gps; SDK_InitGPSData(&gps); // get the current gps position SDK_ERROR rc = GPSManager::getInstance()->getCurrentPosition(gps); start.x = gps.GPSPositionMerc.x; start.y = gps.GPSPositionMerc.y; SDK_Tour * tour; SDK_CreateTour(&tour, start); SDK_AddStationToTour(tour, mDestination); SDK_INT2 sectionError = 0; rc = SDK_CalculateTour(tour, progressCallback, §ionError); SDK_DeleteTour(tour); if (rc == SDK_ERROR_Ok) { SDK_Position pos; SDK_InitPosition(&pos); pos.x = mDestination.x; pos.y = mDestination.y; mMap->setTargetPin(pos); } emit finished((int)rc); } SDK_INT4 SDK_API CalcRouteRunnable::progressCallback(SDK_INT4 current, SDK_INT4 total, SDK_INT4 job) { emit pThis->progress(current); return 1; }
Standard route and tour calculations are all done with the function SDK_CalculateTour(). This function needs an SDK_Tour object which holds the start position and one or multiple stations. The SDK_Tour must first be created with SDK_CreateTour(). It will set the given station as the start station. After creating the SDK_Tour, you can add one or more stations to it by calling SDK_AddStationToTour() or SDK_AddSVPsToTour(). For now, we only want to calculate a so called A-B route with a start station and a standard station as the destination.
So first, we create the tour by calling:
SDK_Tour * tour; SDK_CreateTour(&tour, start);
This will create an SDK_Tour with "start" as the start station. Adding the destination is done with:
SDK_AddStationToTour(tour, mDestination);
We add our destination with SDK_AddStationToTour() to our SDK_Tour. SDK_AddStationToTour() adds a so called "regular" station to the tour. This type of station has only a coordinate and an optional course. It is also possible to add a way path to the tour which should be followed by calling SDK_AddSVPsToTour(). We will cover this topic in Tutorial10.
Then we call:
rc = SDK_CalculateTour(tour, progressCallback, §ionError); SDK_DeleteTour(tour);
to calculate the route. The sectionError variable is used to get a detailed error description if we have a multi station tour. It will be set to the route snippet where the error occurred. We also delete the tour we created, because we don't need it anymore.
SDK_CalculateTour() has the following parameters:
Type | Parameter | Description |
---|---|---|
const SDK_Tour* | tour | The tour which should be calculated |
SDK_ProgressCBFuncT | pCallBackFunc | Optional pointer to a callback method, indicates the actual status of the routing progress |
SDK_INT2* | pSectionErrorBelongsTo | If an error returns, the error belongs to the returned tour section |
We also implemented a callback for showing the progress in a dialog box. CalcRouteRunnable::progressCallback()
will be called by the SDK with the current progress. We emit this progress to our GUI thread (we later connect this signal to a slot in our MainWindow to show the progress in a progress dialog).
Attention
Try to avoid calling other NavigationSDK methods on another thread while the route calculation is running. For example drawing the map on the GUI thread while calculating the route will lock the GUI thread because most NavigationSDK methods are protected by the same mutex and cannot be called in a concurrent way.
To avoid calling other NavigationSDK methods on another thread, we push our NavigationLoop and the SDK_SetLocation() method from our GPSManager also to the SDKJobQueue.
The NavigationLoop will be pushed in the updateTimer()
function, so we change MainWindow::updateTimer().
Change the following in the MainWindow class:
MainWindow.cpp:
void MainWindow::updateTimer() { if(mTimerEnabled) SDKJobQueue::getInstance()->push(mNavigationLoop); }
Instead of calling directly the run() function of the NavigationLoop as in our last Tutorial, we now push the runnable to the queue (which will call the run() method of the NavigationLoop itself).
Second, we created a new class GPSPushLocationRunnable that we can push to the queue instead of calling SDK_SetLocation() directly.
Take a look at it's run()
function:
void GPSPushLocationRunnable::run() { SDK_ERROR rc = SDK_SetLocation(&mGPSData); }
The only thing to do is to call SDK_SetLocation() in it.
In the GPSManager::positionUpdated()
function, we push the GPSPushLocationRunnable to the queue.
We first add the needed headers and then change the positionUpdated function.
Add/Change the following in the GPSManager class:
GPSManager.cpp:
... #include "SDKJobQueue.h" #include "GPSPushLocationRunnable.h" ... void GPSManager::positionUpdated(const SDK_GPSData& gpsData) { SDKJobQueue::getInstance()->push(new GPSPushLocationRunnable(gpsData)); } ...
To avoid rendering the map while calculating the route (which would lock the GUI thread), we add a check to almost every MapWidget function that calls an SDK method (we check mUpdatesAllowed, which must be set from outside the MapWidget).
Also, because we now have a target we would like to show on our map, we add a new function to add and remove a target pin.
To show the route trace after the route calculation, we have to call the function SDK_SendMapViewEvent() in our paintEvent() with an SDK_NavigationInformation struct. If this is 0, no route trace will be rendered, even if there is one available. Calling the function with a freshly initialized struct is sufficient to show the route trace.
To nicely zoom the map view to the route trace after the route calculation, we added also a function called MapWidget::zoom2route():
void MapWidget::zoom2Route() { if (!mUpdatesAllowed) return; SDK_ERROR rc = SDK_SetMapViewParameter(mMapId, SDK_SV_ZoomToRoute, 0, 0, 0, 0, 0, 0); } ... void MapWidget::setMapMarker(const SDK_Position& pos, SDK_INT4 course, bool northenAdjusted, SDK_INT4 mapMarkerStyle) { if (!mUpdatesAllowed) return; ... } ... void MapWidget::paintEvent(QPaintEvent *event) { if (mUpdatesAllowed) { SDK_ERROR rc = SDK_SendMapViewEvent(mMapId, mNavigationInformation, SDK_wmPAINT, 0, 0, mBuffer); } ... } ... void MapWidget::setTargetPin(const SDK_Position& pos) { if (mTargetPinId < 0) SDK_AddImage(L"arw_destination.png", L"", &pos, &mTargetPinId); else SDK_PositionImage(mTargetPinId, &pos); } void MapWidget::removeTargetPin() { if (mTargetPinId >= 0) { SDK_DeleteImage(mTargetPinId); mTargetPinId = -1; } } void MapWidget::removeAllPins() { SDK_DeleteImages(); mPinId = -1; mTargetPinId = -1; }
We added for all relevant functions that could be called in a thread a check if updates are allowed to avoid locking the GUI thread. This is only a very simple approach to for this. As you can see, if updates are not allowed, we do nothing or return a default value. It would be better to buffer the values if an update is not allowed and set them afterwards when updates are allowed again. But this would make the code less readable, so we didn't do this in this tutorial.
To get all to work, we have to
add the following to the MainWindow class:
MainWindow.h
... #include "CalcRouteRunnable.h" #include <QProgressDialog> ... private: SDK_NavigationInformation * mNavigationInformation; QProgressDialog * mProgressDialog; SDK_Position mCurrentDestination; ...
We add the SDKJobQueue header to the MainWindow, initialize our progress dialog pointer to 0 and setAutoDelete() of our NavigationLoop to false (if the flag is set to true in a QRunnable, the runnable will be automatically deleted after execution. We do not want this, so we set the flag to false).
Also, we give a newly created SDK_NavigationInformation struct to the MapWidget to be able to show the route trace.
Add the following to the MainWindow class:
MainWindow.cpp:
... #include "SDKJobQueue.h" ... MainWindow::MainWindow(QMainWindow * parent) : QMainWindow(parent) { ... mProgressDialog = 0; mNavigationLoop->setAutoDelete(false); mNavigationInformation = new SDK_NavigationInformation; SDK_InitNavigationInformation(mNavigationInformation); ui.map->setNavigationInformation(mNavigationInformation); }
Change the destructor so it looks like this:
MainWindow:: ~MainWindow() { if (mTimer) { mTimer->stop(); delete mTimer; } SDKJobQueue::getInstance()->waitForDone(); if (mNavigationLoop) delete mNavigationLoop; if (mProgressDialog) delete mProgressDialog; if (mNavigationInformation) delete mNavigationInformation; mGPSManager.closeGPS(); }
First, we stop pushing the NavigationLoop to the queue by stopping the timer. Then we call SDKJobQueue::getInstance()->waitForDone()
to wait for an eventually running thread job to end to avoid a crash when the MainWindow will be destroyed but the thread still want to access a member of our MainWindow.
We also delete the progress dialog and the mNavigationInformation member.
Our MainWindow::actionSearchAddressTriggered()
function (this is where we create the search dialog and react on the result of it) must be altered.
Change the following in the MainWindow class:
MainWindow.cpp:
void MainWindow::actionSearchAddressTriggered(bool triggered) { disableNavigationLoopTimer(); SDKJobQueue::getInstance()->waitForDone(); SDK_SearchResult result; SDK_InitSearchResult(&result); int retVal = 0; SDK_ERROR rc = SDK_ERROR_UnInitialized; ui.map->removeTargetPin(); // to ensure, that the destructor of SearchDialog and with it the finalization of the mapview in it is called before we // start to calculate a route (which would end in a mutex lock), we enclose the creation in brackets { SearchDialog dialog(this); retVal = dialog.exec(); if (retVal == QDialog::Accepted) { // get the result from the search dialog rc = dialog.getCurrentSearchResult(result); } } if (retVal == QDialog::Accepted && rc == SDK_ERROR_Ok) { ui.map->denyUpdates(); SDK_InitPosition(&mCurrentDestination); mCurrentDestination = result.pos; // setDefaultRoutingOptions(); if (!mProgressDialog) { mProgressDialog = new QProgressDialog("Calculating route...", "Cancel", 0, 100, this, Qt::WindowSystemMenuHint | Qt::WindowTitleHint); mProgressDialog->setWindowModality(Qt::WindowModal); mProgressDialog->setCancelButton(0); } else mProgressDialog->show(); CalcRouteRunnable * runnable = new CalcRouteRunnable(mCurrentDestination, ui.map); connect(runnable, SIGNAL(progress(int)), this, SLOT(onProgress(int))); connect(runnable, SIGNAL(finished(int)), this, SLOT(onCalcRouteFinished(int))); SDKJobQueue::getInstance()->push(runnable); } else enableNavigationLoopTimer(); }
Again, first we wait for our job queue to finish a running task to not get in a mutex lock situation. Then, we start the SearchDialog. If the user clicked a result and the result is valid, we call
ui.map->denyUpdates();
to avoid manipulating the map by panning or something else that would end in a GUI thread lock.
If the progress dialog is not already created, we do this now and create our CalculateRouteRunnable with the destination and our map view as parameters (the map view parameter is used to allow the runnable to set the target pin on the map). We set the destination to the result we got above and connect the progress()
and finished()
signals of the CalcRouteRunnable to the slots MainWindow::onProgress()
and MainWindow::onCalcRouteFinished()
.
Then we push the runnable to the job queue. This will spawn a new thread, in which the run() method of our runnable will be called.
Retrieving progress information
Users should be notified about the progress of every long lasting operation so most of the long lasting operations in the NavigatioSDK can be called with an optional callback that is called frequently by the SDK with updated progress information.
Attention
The callback will be called from the thread in which the route calculation was started from. So in our example from the SDKJobQueue thread. To update a GUI element, we have to bring the execution back to the GUI thread. This is automatically done by Qt with the signal/slot functionality. Signals in Qt have the nice feature that they are internally sent by an event to the GUI threads event loop if the sender runs not in the same thread as the receiver, so onProgress() is called on the GUI thread and we can update the progress dialog safely.
Add the following to the MainWindow class:
MainWindow.h:
... protected slots: void onCalcRouteFinished(int error); void onProgress(int progress); ...
MainWindow.cpp:
... void MainWindow::onProgress(int progress) { if (mProgressDialog) mProgressDialog->setValue(progress); } void MainWindow::onCalcRouteFinished(int error) { ui.map->allowUpdates(); enableNavigationLoopTimer(); if ((SDK_ERROR)error == SDK_ERROR_Ok) { ui.map->zoom2Route(); ui.map->update(); } } ...
When a new progress event arrives, we update the progress dialog:
After the route calculation has finished, the onCalcRouteFinished() slot will be called where we again allow updates of the map. We also reenable the NavigationLoop timer. The CalculateRouteRunnable sends the returned error code from SDK_CalculateTour() after the calculation, so we check this and if the route calculation succeeded, we zoom the map to show the whole route:
RoutingOptions
The NavigationSDK brings several methods to influence the result of the route calculation. For example you can avoid toll roads, decide, what kind of vehicle you are driving or if you want a routing optimized for short way or short time. You can manually change every single routing parameter if you wish, but many of the parameters need a deeper knowledge on how they influence the routing to get the wanted effect on the route (like the speed tables).
Loading a vehicle profile
To avoid setting the routing options manually and to get a quick way to set them for a particular vehicle, we use so called profiles which describes certain standard vehicles like trucks, cars, transporters and so on. In these profiles (which are text files) the values for the relevant routing and lorry options are preset (some of the options are not in the profiles file, but will be adapted internally to the used vehicle). We highly recommend to use the profile loading mechanism which the SDK provides instead of setting the options manually, especially the speed tables.
Loading a profile is done by calling the method SDK_LoadVehicleProfile(). The function takes as parameter the full path to the profile file which should be loaded.
We deliver a set of profiles in a directory called 'profiles' under the data directory of the tutorial app data.
Add the following to the MainWindow class:
MainWindow.h:
... protected: void loadProfile(); ...
MainWindow.cpp:
... MainWindow::MainWindow(QMainWindow * parent) : QMainWindow(parent) { ... loadProfile(); } void MainWindow::loadProfile() { QString profilePath = Constants::getDataPath() + "profiles/truck75.dat"; SDK_ERROR rc = SDK_LoadVehicleProfile(profilePath.toStdWString().c_str()); if (rc == SDK_ERROR_Ok) { SDK_WCHAR_T * profileName = 0; rc = SDK_GetProfileName(profilePath.toStdWString().c_str(), L"GB", &profileName); if (rc == SDK_ERROR_Ok) { QString profileNameQt = QString::fromStdWString(profileName); free(profileName); QString outputMessage = "Loaded profile: "; outputMessage += profileNameQt; statusBar()->showMessage(outputMessage); } } } ...
We load the profile "truck75.dat" which has all options set for a 7.5t truck. We also set the status bar text to the english translation of the profile name by calling SDK_GetProfileName().
SDK_GetProfileName() has the following parameters:
Type | Parameter | Description |
---|---|---|
const SDK_WCHAR_T * | pFileName | The name of the profile file (with full path) which should be loaded |
const SDK_WCHAR_T * | cc | The country code for the wanted translation, if null, english will be returned (if available) |
SDK_WCHAR_T ** | pProfileName | The translated name of the profile |
The cc is of type SDK_ccf_ISO_2. See the documentation for more details.
Manually setting the routing options
Setting the routing options manually is also possible. As you can see in the list below, there are a bunch of options which could be set. Some of these should only be changed manually if a deeper knowledge of the parameter is given. We highly recommend to use the profile loading functionality described above for a start.
In our example, we set one option manually: The RouteCalculationType. This decides if alternative routes should be calculated or not. Because we don't want alternatives in this tutorial, we set the option to 'SDK_RouteClassic' in MainWindow::setDefaultRoutingOptions()
.
Before setting an option, we call SDK_GetRoutingOptions() to retrieve the current set SDK_RouteOptions. Afterwards, we alter the RouteCalculationType and write the options back with SDK_SetRoutingOptions().
The struct SDK_RouteOptions has the following members:
Type | Name | Description |
---|---|---|
SDK_HDRINFO | size | Size of struct - for controlling |
SDK_HDRINFO | version | version of the structure - for controlling. Use \ref SDK_RouteOptionsVERSION |
SDK_INT4 | TimeFactor | This parameter can be used to set the desired time factor. This factor can be used to influence the weight of distance and duration in the evaluation of routes. If set to 0 the time has no influence and the shortest route is searched.If the factor is set to 100 (%) time is considered as very important so the result is the fastest route prefering motorways and fast by-passes. |
SDK_INT4 | AltRoute | This parameter can be used to set the alternative route that should be exported. At the moment 1 alternative route is supported. This default route has to be calculated first! 0 indicates default route, 1 the alternative route |
SDK_INT4 | AltRouteMalus | This parameter can be used to set the AltRoutesMalus. This malus makes it possible to influence how greatly the alternative route may deviate from the basic route. Streets that were already be used in the privious routes are considered more "expensive" in subsequent calculations.Not yet implemented |
SDK_BOOL | RouteWithoutAutoroute | Flag for controlling whether the route should avoid motorways. This is only supported for routes up to 150km. For longer distances the route may again use motorways. |
SDK_BOOL | RouteWithoutFerry | Flag for controlling whether the route should avoid ferries. |
SDK_SpeedTable | SpeedTable_Calc | This method can be used to set the desired speed profile for route calculation. RoutingVehicle=SDK_rvUSER has to be specified to make this table become active! These are always scaled in steps of three speeds (fast, medium and slow) for motorways, national, country, urban, access roads and ferries. The values are in km/h independently of the option UseMetricSystem. Users should avoid using modified speedtables if possible! |
SDK_SpeedTable | SpeedTable_RouteList | vThis method can be used to set the desired speed profile for the route list (calculation of times). RoutingVehicle=SDK_rvUSER has to be specified to make this table become active! These are always scaled in steps of three speeds (fast, medium and slow) for motorways, national, country, urban, access roads and ferries. The values are in km/h. (independent of the option UseMetricSystem!) Users should avoid using modified speedtables if possible! |
SDK_INT4 | UTurnMalus | This parameter allows to control the handling of U-turns during the route-calculation. The value specifies, how much longer an alternative way without U-turn can be, before the shorter way with a U-turn is used. Allowed values range from 0 to 50000 seconds as impact for the route with U-turn. |
SDK_INT4 | RoutingVehicle | Vehicle Type. See \ref RoutingVehicles |
SDK_INT4 | MatchDistStart | Distance for road matching at the start [Mercator units]. Mercator units for central europe are 1-2m; for a detailled conversion please use \ref SDK_TransformCoordinates |
SDK_INT4 | MatchDistDestination | Distance for road matching at the destination [Mercator units]. Mercator units for central europe are 1-2m; for a detailled conversion please use \ref SDK_TransformCoordinates |
SDK_BOOL | AvoidFerryOnStart | If SDK_TRUE don't link to ferries on start. May be useful if the start is in an offroad position. |
SDK_BOOL | AvoidFerryOnDestination | If SDK_TRUE don't link to ferries on destination. May be useful if the destination is in an offroad position. |
SDK_BOOL | AvoidMotorwayOnStart | If SDK_TRUE don't link to motorways on start. May be useful if the start is in an offroad position. |
SDK_BOOL | AvoidMotorwayOnDestination | If SDK_TRUE don't link to motorways on destination. May be useful if the destination is in an offroad position. |
SDK_BOOL | bAvoidTunnelOnStart | If SDK_TRUE don't link to tunnels on start.May be useful if the start is in an offroad position. |
SDK_BOOL | bAvoidTunnelOnDestination | If SDK_TRUE don't link to tunnels on destination. May be useful if the destination is in an offroad position. |
SDK_BOOL | bAvoidPedestrianZoneOnStart | If SDK_TRUE don't link to Segments in pedestrianzones on start |
SDK_BOOL | bAvoidPedestrianZoneOnDestination | If SDK_TRUE don't link to segments in pedestrianzones on destination |
SDK_BOOL | bPedestrianRoutingFromStart | If SDK_TRUE the route leads to the nearest Segment outside the pedestrian zone an a trace through the pedestrian zone is added to the route. In the pedastrian zone itself will be no guidance! Does not work with bAvoidPedestrianZoneOnDestination == true! |
SDK_BOOL | bPedestrianRoutingToDestination | If SDK_TRUE the route leads to the nearest Segment outside the pedestrian zone an a trace through the pedestrian zone is added to the route. In the pedastrian zone itself will be no guidance! Does not work with bAvoidPedestrianZoneOnDestination == true! |
SDK_BOOL | bPremisesRouting | If SDK_TRUE, it's possible to route through gates of premises at start and target. |
SDK_BOOL | bViolateLorryRescrictions | If SDK_TRUE, it's possible to ignore LorryRestrictions at start and target. |
SDK_BOOL | Lorry | Set lorry restrictions which should be taken into consideration during route calculation. |
SDK_BOOL | bNiceTransit | If set to SDK_TRUE a cross map routing will use detail level maps in transit countries if available. Otherwise it will only use the MR map which reduces the memory impact and reduces time for route calculation. |
SDK_BOOL | bForceMRRouting | If set to SDK_TRUE a cross map routing will be formed even if start and destination are within the same map. Otherwise it will only use the local map which reduces the memory impact and reduces time for route calculation. |
SDK_BOOL | bUseRRTLayers | If set to SDKK_TRUE then .rrt layers will be evaluated for route calculation. Default is SDK_TRUE. |
SDK_INT1 | ClassOfDangerousGoods | Class of dangerous goods. May be 'A', 'B', 'C', 'D', 'E'.
|
SDK_BOOL | bUseTollLayer | If set to SDK_TRUE then layers with toll (.lot) will be evaluated for route calculation. Default is SDK_FALSE. |
SDK_UINT4 | TollFactor | The factor is to be understood as % additional charge of cost of a segments with toll. Default is 150. |
SDK_BOOL | bUseTruckTollLayer | If set to SDK_TRUE then layers with trucktoll (.etx) will be evaluated for route calculation. Default is SDK_FALSE. |
SDK_UINT4 | TruckTollFactor | The factor is to be understood as % additional charge of cost of a segments with trucktoll. Default is 100. |
SDK_INT4 | AmountIgnoredTiles | count of tiles in the start/target zone |
SDK_UINT1 | AdditionalCostFactorRestrictionArea | additional costs in % for ignored truck segments in start/target zone (max 256) |
SDK_BOOL | bOpenGenerelRestrictions | ignore generell truck restriction in the start/target zone |
SDK_BOOL | bOpenGenerelRestrictionsAndWeight | ignore generell and weight truck restrictions in the start/target zone |
SDK_BOOL | bOpenDeliveryRestrictions | ignore restrictions with residential or delivery flag |
SDK_UINT4 | TrafficFactor | The factor is to be understood as a switch to turn on and off the traffic consideration while calculating a route. 0 means do not consider traffic while route calculation, > 0 means consider it |
SDK_INT4 | RouteCalculationType | Route calculation type, like standard or with alternatives. See RouteCalculationTypes |
Add the following to the MainWindow class:
MainWindow.h:
... protected: void setDefaultRoutingOptions(); ...
MainWindow.cpp:
void MainWindow::setDefaultRoutingOptions() { SDK_RouteOptions routeOptions; SDK_InitRouteOptions(&routeOptions); SDK_ERROR rc = SDK_GetRoutingOptions(&routeOptions); routeOptions.RouteCalculationType = SDK_RouteClassic; rc = SDK_SetRoutingOptions(&routeOptions); }
We could call this function in our actionSearchAddressTriggered() before starting the route calculation:
void MainWindow::actionSearchAddressTriggered(bool triggered) { ... if (retVal == QDialog::Accepted && rc == SDK_ERROR_Ok) { ... setDefaultRoutingOptions(); if (!mProgressDialog) { ... } else ... CalcRouteRunnable * runnable = new CalcRouteRunnable(mCurrentDestination, ui.map); ...