Skip to content
This repository has been archived by the owner on Dec 4, 2018. It is now read-only.

Commit

Permalink
Merge OSM Scout routers into one (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
rinigus authored and otsaloma committed Jun 23, 2017
1 parent 49b6e4a commit 550f60d
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 242 deletions.
6 changes: 6 additions & 0 deletions poor/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ def _migrate(self, values):
# Impose new default providers introduced in 0.25.
for option in ("geocoder", "guide", "router"):
values[option] = DEFAULTS[option]
if version < (0,30):
# libosmscout and Valhalla routers merged in 0.30.
# https://github.com/otsaloma/poor-maps/pull/41
routers = values.setdefault("routers", {})
routers.pop("osmscout", None)
routers.pop("osmscout_valhalla", None)
return values

def read(self, path=None):
Expand Down
4 changes: 2 additions & 2 deletions routers/osmscout.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"attribution": "Data © OpenStreetMap contributors",
"_description": "Routing based on OpenStreetMap data",
"_modes": "car, bicycle, foot",
"name": "OSM Scout libosmscout",
"requires": ["harbour-osmscout-server"],
"name": "OSM Scout",
"requires": ["harbour-osmscout-server", "harbour-osmscout-server-module-route"],
"_source": "OSM Scout offline server"
}
97 changes: 82 additions & 15 deletions routers/osmscout.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,59 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
Routing using OSM Scout Server.
Routing using OSM Scout Server's Valhalla and libosmscout routers.
https://github.com/rinigus/osmscout-server
https://github.com/valhalla/valhalla-docs/blob/master/api-reference.md
"""

import copy
import json
import poor
import urllib.parse

CONF_DEFAULTS = {"type": "car"}
CONF_DEFAULTS = {"type": "auto"}

ICONS = {
ICONS = { 0: "flag",
1: "depart",
2: "depart-right",
3: "depart-left",
4: "arrive",
5: "arrive-right",
6: "arrive-left",
7: "continue",
8: "continue",
9: "turn-slight-right",
10: "turn-right",
11: "turn-sharp-right",
12: "uturn",
13: "uturn",
14: "turn-sharp-left",
15: "turn-left",
16: "turn-slight-left",
17: "continue",
18: "off-ramp-slight-right",
19: "off-ramp-slight-left",
20: "off-ramp-slight-right",
21: "off-ramp-slight-left",
22: "fork-straight",
23: "fork-slight-right",
24: "fork-slight-left",
25: "merge-slight-left",
26: "roundabout",
27: "off-ramp-slight-right",
28: "flag",
29: "flag",
30: "flag",
31: "flag",
32: "flag",
33: "flag",
34: "flag",
35: "flag",
36: "flag",
}

ICONS_OSMSCOUT = {
"destination": "arrive",
"flag": "flag",
"merge": "merge-slight-left",
Expand All @@ -46,36 +87,62 @@
"turn-slight-right": "turn-slight-right",
}

URL = "http://localhost:8553/v1/route?type={type}"
URL = "http://localhost:8553/v2/route?json={input}"
cache = {}

def render_endpoint(i, point):
"""Return URL component for given endpoint."""
def prepare_endpoint(point):
"""Return `point` as a dictionary ready to be passed on to the router."""
if isinstance(point, (list, tuple)):
return ("&p[{i:d}][lng]={x:.6f}&p[{i:d}][lat]={y:.6f}"
.format(i=i, x=point[0], y=point[1]))
point = urllib.parse.quote_plus(point)
return "&p[{i:d}][search]={point}".format(i=i, point=point)
return dict(lat=point[1], lon=point[0])
geocoder = poor.Geocoder("osmscout")
results = geocoder.geocode(point, dict(limit=1))
return prepare_endpoint((results[0]["x"], results[0]["y"]))

def route(fm, to, params):
"""Find route and return its properties as a dictionary."""
type = poor.conf.routers.osmscout.type
fm, to = map(prepare_endpoint, (fm, to))
lang = poor.util.get_default_language("en")
input = dict(locations=[fm, to],
costing=poor.conf.routers.osmscout.type,
directions_options=dict(language=lang))

input = urllib.parse.quote(json.dumps(input))
url = URL.format(**locals())
for i, point in enumerate((fm, to)):
url += render_endpoint(i, point)
with poor.util.silent(KeyError):
return copy.deepcopy(cache[url])
result = poor.http.get_json(url)
if result.get("API version", "") == "libosmscout V1":
return parse_result_libosmscout(url, result)
return parse_result_valhalla(url, result)

def parse_result_libosmscout(url, result):
"""Parse and return route from libosmscout engine."""
x, y = result["lng"], result["lat"]
maneuvers = [dict(
x=float(maneuver["lng"]),
y=float(maneuver["lat"]),
icon=ICONS.get(maneuver.get("type", "flag"), "flag"),
icon=ICONS_OSMSCOUT.get(maneuver.get("type", "flag"), "flag"),
narrative=maneuver["instruction"],
duration=float(maneuver["time"]),
length=float(maneuver["length"]),
) for maneuver in result["maneuvers"]]
route = dict(x=x, y=y, maneuvers=maneuvers)
route = dict(x=x, y=y, maneuvers=maneuvers, engine="libosmscout")
if route and route["x"]:
cache[url] = copy.deepcopy(route)
return route

def parse_result_valhalla(url, result):
"""Parse and return route from Valhalla engine."""
legs = result["trip"]["legs"][0]
x, y = poor.util.decode_epl(legs["shape"], precision=6)
maneuvers = [dict(
x=float(x[maneuver["begin_shape_index"]]),
y=float(y[maneuver["begin_shape_index"]]),
icon=ICONS.get(maneuver["type"], "flag"),
narrative=maneuver["instruction"],
duration=float(maneuver["time"]),
) for maneuver in legs["maneuvers"]]
route = dict(x=x, y=y, maneuvers=maneuvers, engine="Valhalla")
if route and route["x"]:
cache[url] = copy.deepcopy(route)
return route
7 changes: 5 additions & 2 deletions routers/osmscout_results.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Page {
property bool loading: true
BusyModal {
id: busy
description: qsTranslate("", "For long routes, this could take up to a minute.")
running: page.loading
}
onStatusChanged: {
Expand All @@ -50,7 +49,11 @@ Page {
"x": route.x,
"y": route.y,
"mode": "car",
"attribution": qsTranslate("", "Routing courtesy of %1.").arg("OSM Scout Server")
// TRANSLATORS: %1 refers to the routing engine, %2 to the service.
"attribution": (qsTranslate("", "Routing by %1, courtesy of %2")
.arg(route.engine)
.arg("OSM Scout Server"))

});
map.hidePoiBubbles();
map.fitViewToRoute();
Expand Down
2 changes: 1 addition & 1 deletion routers/osmscout_settings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Column {
MenuItem { text: qsTranslate("", "Bicycle") }
MenuItem { text: qsTranslate("", "Foot") }
}
property var keys: ["car", "bicycle", "foot"]
property var keys: ["auto", "bicycle", "pedestrian"]
Component.onCompleted: {
var key = app.conf.get("routers.osmscout.type");
typeComboBox.currentIndex = typeComboBox.keys.indexOf(key);
Expand Down
8 changes: 0 additions & 8 deletions routers/osmscout_valhalla.json

This file was deleted.

105 changes: 0 additions & 105 deletions routers/osmscout_valhalla.py

This file was deleted.

68 changes: 0 additions & 68 deletions routers/osmscout_valhalla_results.qml

This file was deleted.

Loading

0 comments on commit 550f60d

Please sign in to comment.