# -*- coding: utf-8 -*-
"""Interaction with the Open Source Routing Machine.
This module contains functions that send requests to the OSRM routing engine. A running
OSRM server is required.
.. _OSRM documentation:
http://project-osrm.org/
"""
# External imports.
import logging
import os
import requests
# Internal imports.
from routingtools import _utils
from routingtools.exceptions import OSRMError
# Log settings.
logger = logging.getLogger(__name__)
# Server settings.
osrm_server = os.getenv("OSRM_SERVER_URL", "http://localhost:5000")
[docs]def get_cost_matrix(cost, coords):
"""
Retrieves a matrix from the OSRM routing engine, describing the travel cost between two
locations, for each possible combination of locations.
Args:
cost (str): The type of travel cost to be used, either 'duration' or 'distance'.
coords (list): List of coordinate pairs, where each coordinate pair describes a
location in geographical space and is a list [a, b] with a and b being respectively
the longitude and latitude coordinates of the location. Dummy locations, with a
coordinate value of [None] instead of [a, b], will be ignored.
Returns:
list: A list in which each element is again a list.
Each of those sub-lists is representing a single row of the cost matrix, and each of
its elements is an integer describing the calculated travel cost between the two
respective locations.
"""
# Compose request.
# Only include real coordinates, i.e. a list of length 2 with longitude and latitude.
# Coordinates of a dummy node (i.e. [None]) should not be included.
url_type = osrm_server + "/table/v1/driving/"
url_coords = ";".join([str(x[0]) + "," + str(x[1]) for x in coords if len(x) == 2])
url_cost = "?annotations=" + cost
url = url_type + url_coords + url_cost
logger.debug("Composed an OSRM matrix request: {}".format(url))
# Send request.
raw_response = requests.get(url)
response = raw_response.json()
if not raw_response.ok:
raise OSRMError("Failed to retrieve cost matrix: " + response["message"])
# Keep only the cost matrix, and not all its attributes.
# Round the values to their nearest integer because Google OR Tools requires integers.
matrix = _utils._convert_matrix_values_to_integers(response[cost + "s"])
logger.info("Retrieved a {} matrix from OSRM with {} nodes".format(cost, len(matrix)))
return matrix
[docs]def get_route(coords):
"""
Retrieves the shortest route between multiple locations from the OSRM routing engine.
The locations will be visited in the order they are provided.
Args:
coords (list): List of coordinate pairs, where each coordinate pair describes a
location in geographical space and is a list [a, b] with a and b being respectively
the longitude and latitude coordinates of the location. Dummy locations, with a
coordinate value of [None] instead of [a, b], will be ignored.
Returns:
dict: An OSRM route result - http://project-osrm.org/docs/v5.5.1/api/#result-objects.
"""
# Compose request.
# Only include real coordinates, i.e. a list of length 2 with longitude and latitude.
# Coordinates of a dummy node (i.e. [None]) should not be included.
url_type = osrm_server + "/route/v1/driving/"
url_coords = ";".join([str(x[0]) + "," + str(x[1]) for x in coords if len(x) == 2])
url_options = "?overview=full&geometries=geojson"
url = url_type + url_coords + url_options
logger.debug("Composed an OSRM route request: {}".format(url))
# Send request.
raw_response = requests.get(url)
response = raw_response.json()
if not raw_response.ok:
raise OSRMError("Failed to retrieve cost matrix: " + response["message"])
# Keep only the routes object, and not all its attributes.
routes = response["routes"]
logger.info("Retrieved a route from OSRM with {} nodes".format(len(coords)))
return routes