For my question I have prepared a jsFiddle demo requiring you to click at the map 5 times:
If I understand this correctly, the OSRM does not care about ways.
It only cares about nodes and their probabilities as shown in A Practical Guide to an Open-Source Map-Matching Approach for Big GPS Data:
However for my app the map-matched ways are needed, to achieve better road coverage:
'use strict';
function processOsrmReply(data) {
console.log('Received OSRM map matching reply:');
console.log(data);
if (data.code !== 'Ok') {
clearMap('OSRM error code: ' + data.code);
return;
}
for (var m = 0; m < data.matchings.length; m++) {
var matching = data.matchings[m];
var coordinates = matching.geometry.coordinates;
// alternate line colors to see the different matchings
var lineColor = (m % 2 === 0 ? 'red' : 'darkred');
var latLngs = coordinates.map(coordinate => [coordinate[1], coordinate[0]]);
L.polyline(latLngs, { color: lineColor }).addTo(osrmNodesGroup);
for (var l = 0; l < matching.legs.length; l++) {
var leg = matching.legs[l];
var nodes = leg.annotation.nodes;
console.log('matching ' + m + ', leg ' + l + ' contains the nodes:');
console.log(nodes);
sendOverpassRequest(nodes);
}
}
}
function sendOsrmRequest() {
// get the currently displayed markers
var markers = markersGroup.getLayers();
// create an array of string: "lng,lat" with 6 digits after comma
var lngLats = markers.map(marker =>
parseFloat(marker.getLatLng().lng).toFixed(6) + ',' +
parseFloat(marker.getLatLng().lat).toFixed(6)
);
// create an array of radiuses, same length as lngLats array
var radiuses = lngLats.map(lngLat => 50);
var url = 'https://router.project-osrm.org/match/v1/driving/' +
lngLats.join(';') +
'?overview=simplified' +
'&radiuses=' +
radiuses.join(';') +
'&generate_hints=false' +
'&skip_waypoints=true' +
'&gaps=ignore' +
'&annotations=nodes' +
'&geometries=geojson';
console.log('Sending OSRM map matching query to the URL ' + url);
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var data = JSON.parse(this.response);
processOsrmReply(data);
} else {
clearMap('OSRM error status: ' + this.status);
}
};
request.send();
}
function processOverpassReply(data) {
console.log('Received Overpass API reply with ' + data.elements.length + ' elements');
console.log(data.elements);
for (var w = 0; w < data.elements.length; w++) {
var element = data.elements[w];
if (element.type === 'way') {
var wayId = element.id;
// alternate line colors to see the different ways
var lineColor = (w % 2 === 0 ? 'blue' : 'navy');
var latLngs = element.geometry.map(geom => [geom.lat, geom.lon]);
L.polyline(latLngs, { color: lineColor }).addTo(overpassWaysGroup);
}
}
}
function sendOverpassRequest(nodes) {
var query = 'node(id:' + nodes.join(',') + '); way[highway](bn); out geom;'
console.log('Sending Overpass API query: ' + query);
var url = 'https://overpass-api.de/api/interpreter?data=[out:json];' + query;
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var data = JSON.parse(this.response);
processOverpassReply(data);
} else {
clearMap('Overpass error status: ' + this.status);
}
};
request.send();
}
function processMapClick(ev) {
// get the currently displayed markers
var markers = markersGroup.getLayers();
if (markers.length < MARKERS_MAX) {
L.marker(ev.latlng).addTo(markersGroup);
return;
}
// get the count of currently displayed polylines
var linesCount = osrmNodesGroup.getLayers().length;
if (linesCount > 1) {
clearMap();
return;
}
sendOsrmRequest();
}
function clearMap(str = '') {
var hint = document.getElementById('hint');
hint.textContent = str;
// remove polylines and markers
osrmNodesGroup.clearLayers();
overpassWaysGroup.clearLayers();
markersGroup.clearLayers();
}
var MARKERS_MAX = 4;
var map = L.map('map').setView([51.4661, 7.2491], 14).on('click', processMapClick);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// layer groups for markers and polylines
var markersGroup = L.layerGroup();
map.addLayer(markersGroup);
var osrmNodesGroup = L.layerGroup();
map.addLayer(osrmNodesGroup);
var overpassWaysGroup = L.layerGroup();
map.addLayer(overpassWaysGroup);
var overlays = {
'Show <b>markers</b> placed by user': markersGroup,
'Show <b>nodes</b> returned by OSRM': osrmNodesGroup,
'Show <b>ways</b> returned by Overpass': overpassWaysGroup
};
L.control.layers(null, overlays, { collapsed: false }).addTo(map);
html,
body {
padding: 0;
margin: 0;
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
#map {
flex-grow: 1;
}
#hint {
text-align: center;
}
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.css">
<script src="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet-src.js"></script>
<p id="hint">
Click the map 5x to draw the map matched ways!
</p>
<div id="map"></div>
If you set the "Show ways returned by Overpass" checkbox, you will see that the demo is able to retrieve the ways.
However it retrieves too many ways, probably also the ways, which only have one node from the OSRM-returned list of nodes.
Please help me, how to filter out only the map matched ways?
The reason, why I need ways is that my app will collect vehicle data and I want to cover all ways as good as possible, by setting a limit on reports (for example max 10 per day) coming from a way id. In other words: I do not want 10 reports from a busy highway and 0 reports from a nearby forest way. I need 10 reports from the both.