3

I have location values for every driving trip fetched from our servers. I need to generate a single route that is matched to roads, with given locations. I’m using Leaflet Javascript Map Library, OpenStreetMap Tile Map Service and OSRM API Match Service.

I send 100 (parameter limit) locations(latitudes and longitudes) per request, then I append a list with every geometry returned as a response from OSRM Match API. Then I decode every single geometry, result is a list of lats and longs. I combine the result then draw it on a map.

P.S. Time interval between consecutive locations is 1 second.

Some of the locations are well matched to roads as exactly I want.

1

2

But most of the trip is shown on the map with a lot of branching, unrelated lines;

3

4

There are even unmatched, recurring shapes;

5

Here is the explanation of Match Service which is found in official OSRM documentation;

6

Is there a way to generate a single, properly drawn line that’s matched to roads, using these services?

1 Answers1

1

Here a jsFiddle demo, which draws map matched response by OSRM as a blue line:

OpenStreetMap with OSRM map matched route

My Javascript code is below and I have even tested it with about 200 locations recorded by a driving car, after increasing the osrm-routed limit by adding the start parameter --max-matching-size 1000:

'use strict';

function processOsrmReply(data) {

  if (data.code !== 'Ok') {
    clearMap('Error code: ' + data.code);
    return;
  }

  data.matchings.forEach(function(matching) {
    matchesGroup.addData(matching.geometry);
  });
  
  myMap.flyToBounds(matchesGroup.getBounds());
}

function sendOsrmRequest(lngLats) {
  // create an array of radiuses, same length as lngLats array
  var radiuses = lngLats.map(lngLat => 49);

  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';

  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('Error status: ' + this.status);
    }
  };
  request.send();
}

function processMapClick(ev) {
  // get the count of currently displayed markers
  var markersCount = markersGroup.getLayers().length;
  if (markersCount < MARKERS_MAX) {
    L.marker(ev.latlng).addTo(markersGroup);
    matchesGroup.clearLayers();
    return;
  }

  // get the count of currently displayed matches
  var linesCount = matchesGroup.getLayers().length;
  if (linesCount >= 1) {
    clearMap();
    return;
  }

  // create an array of string: "lng,lat" with 6 digits after comma
  var lngLats = markersGroup.getLayers().map(marker =>
    parseFloat(marker.getLatLng().lng).toFixed(6) + ',' +
    parseFloat(marker.getLatLng().lat).toFixed(6)
  );

  sendOsrmRequest(lngLats);
}

function clearMap(str = '') {
  var myStatus = document.getElementById('myStatus');
  myStatus.textContent = str;

  matchesGroup.clearLayers();
  markersGroup.clearLayers();
}

var MARKERS_MAX = 4;
var startPosition = [40.0005, 32.8722];
var myMap = L.map('myMap').setView(startPosition, 14).on('click', processMapClick);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(myMap);

var markersGroup = L.layerGroup();
myMap.addLayer(markersGroup);
var matchesGroup = L.geoJSON();
myMap.addLayer(matchesGroup);
html, body { 
  margin: 0;
  padding: 0;
}

#myMap {
  position: absolute;
  z-index: 1;
  width: 100%;
  height: 100%;
}

#myStatus {
  text-align: center;
  position: absolute;
  z-index: 2;
  width: 100%;
}
<link href="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css" type="text/css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet-src.min.js"></script>

<div id="myStatus">Click 5x at the map to send OSRM map matching request</div>
<div id="myMap"></div>
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416