Routing engines
Vector map data
In the previous post we have described how to prepare functioning map with some overlays added to it. Now, it would be nice to add some other options to it, for example finding a route to your POI’s, or converting addresses to coordinates and back. This is when you need a first data format introduced in the first post (which is vector data), and a pathfinding server (commonly called routing engine). Again, you can use paid solutions, because almost all map providers also provide a routing engine, but of course you can also use open source solution.
Setting your own routing engine
An example of open source routing engine is OSRM (Open Source Routing Machine). It works on the same OpenStreetMap data that you downloaded for your tileserver. You can find build instruction on OSRM project’s webpage: https://github.com/Project-OSRM/osrm-backend. After installing, OSRM provides REST API for all map queries, documented here: http://project-osrm.org/docs/v5.23.0/api/#
Using OSRM in Qt application
Having configured the OSRM server, integrating it with your Qt application is as easy as adding one parameter to the OSM map plugin:
PluginParameter { name: "osm.routing.host" value: "http://insert.your.address.here.com/" }
When routing host is set up, you gain access to geocoding (using classes GeocodeModel and Address) and routing (using classes RouteModel, Route, RouteSegment and RouteManeuver).
Geocoding and reverse geocoding
Geocoding is a process of finding coordinates of a specified address. Reverse geocoding is a process of finding nearest address of specified coordinates. Both of these processes are done via GeocodeModel. You need to set up query property of the model (if you set it to String or Address instance, and it will perform geocoding, while if you will set it to coordinate instance, it will perform reverse geocoding). After setting query, you simply need to call update() method. GeocodeModel will then make a query to the OSRM server and will emit a locationsChanged() signal when finished. To show these results, you could use MapItemView or ListView, with GeocodeModel as their model.
Path finding and navigating
Basic map components available in Qt don’t have navigation – you have to implement your own solution for this. When writing your own navigating algorithm there can be multiple issues that you will need to solve. Here we focus on describing some of the most common problems that may occur when implementing navigation algorithm in Qt.
1. Segments
In QML after the route is found (for RouteModel==1), the route generated in RouteModel consists of longer segments (lets call them paths) that contains shorter segments. The route is stored as a list of paths. Path is a structure containing:
– direction (QString)
– distance to the next instruction (int)
– coordinates of the beginning of the path (QGeoCoordinate)
– instruction (QString)
– list of the consecutive geographical coordinates marking beginnings and ends of the segments in the path (QVariantList).
The problem is that the list can be incorrect. Automatic method of assigning consecutive geographic coordinates to segments is based on the assumption that if there are 2 same consecutive points, they are the end point of one segment and the starting point of the next. And such a situation (2 the same points in a row) also takes place at every intersection. To handle it properly you should write your own method for defining starting and ending points of the segments.
This can be done by checking two conditions:
– are there the same coordinates twice in a row?
– are these coordinates equal to the beginning of the next segment recorded earlier?
If only condition 1 is met, it means that it is not a new segment, but an intersection. If both conditions are met, we start writing to a new segment.
2. BEARING
Takes values between 0 and 359 degree. The problem is that map rotation should be visualized in a way proper for human eye and this process takes some time. If a new bearing was set, the map started to rotate, but if at this time we entered the next section and another bearing value was coming, then the previous one was rotating to the end anyway, and, moreover, the rotation angle for the new segment was counted relative to that previous value which was not set.
To overcome these issues you can use timers and fully control how the map rotates. We used two timers: bearingAddTimer (clockwise rotation) i bearingSubtractTimer (counterclockwise rotation).
Thanks to this:
a) the map was rotating at some normal pace (originally it was too fast),
b) in the solution with timers, in case of a new bearing value, if the previous bearing of the map had not yet been set, the rotation was stopped and the next angle was calculated with respect to the actually set value.
3. Leaving the route
There is a parameter that determines what is the minimal distance from the calculated route that is considered as a point of leaving it. The parameter should be set very carefully. If, for example, we set it at 20m, then when trying to calculate the route, if we were further than 20m from the nearest point at the route, then the new route was not recalculated. For larger values the problem disappeared. How much value is too small? It probably depends, but at 100m it was ok, and at 20m there were big problems. Verify it yourself for your case.
4. Accuracy problems
High accuracy must be turned on, because on some phones (Samsung S7 for example) the GPS location was not enough and the route was reloading all the times with different locations showed up. High location had to be set in Java using JNI.
5. Segment’s filtering
You have to manually remove segments with length equal to 0 if you want rotating to work properly.
Stay tuned as in the next post we will introduce more advanced use of maps in Qt!
There are no comments so far