Skip to content

Commit 21dde0c

Browse files
Merge pull request #14 from nextmv-io/merschformann/fix-osrm-no-route
Adds fallback for OSRM "NoRoute" errors
2 parents a20bc78 + a9676fe commit 21dde0c

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

nextplot/osrm.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ class OsrmRouteRequest:
1616

1717

1818
@dataclasses.dataclass
19-
class OsrRouteResponse:
19+
class OsrmRouteResponse:
2020
paths: list[list[types.Position]]
2121
distances: list[float]
2222
durations: list[float]
2323
zero_distance: bool = False
24+
no_route: bool = False
2425

2526

2627
def query_route(
2728
endpoint: str,
2829
route: OsrmRouteRequest,
29-
) -> OsrRouteResponse:
30+
) -> OsrmRouteResponse:
3031
"""
3132
Queries a route from the OSRM server.
3233
"""
@@ -40,9 +41,26 @@ def query_route(
4041
# Query OSRM
4142
try:
4243
response = requests.get(url)
44+
# If no route was found, use as-the-crow-flies fallback
45+
if response.status_code == 400 and response.json()["code"] == "NoRoute":
46+
print(
47+
f"Warning: OSRM was unable to find a route for {[(p.lat, p.lon) for p in route.positions]}"
48+
+ "(lat,lon ordering), using as-the-crow-flies fallback"
49+
)
50+
paths, distances, durations = [], [], []
51+
for f, t in zip(route.positions, route.positions[1:], strict=False):
52+
paths.append(
53+
[types.Position(lon=f.lon, lat=f.lat, desc=None), types.Position(lon=t.lon, lat=t.lat, desc=None)]
54+
)
55+
distances.append(common.haversine(f, t))
56+
durations.append(common.haversine(f, t) / TRAVEL_SPEED)
57+
return OsrmRouteResponse(paths=paths, distances=distances, durations=durations, no_route=True)
58+
# Make sure we are not getting an error
4359
response.raise_for_status()
4460
except requests.exceptions.RequestException as e:
4561
print(f"Error querying OSRM at {url_base}:", e)
62+
if response:
63+
print(response.text)
4664
sys.exit(1)
4765
result = response.json()
4866
if result["code"] != "Ok":
@@ -85,13 +103,13 @@ def query_route(
85103
print(f"Warning: number of legs ({len(legs)}) does not match number of positions ({len(route.positions)} - 1)")
86104

87105
# Extract route
88-
return OsrRouteResponse(paths=legs, distances=distances, durations=durations, zero_distance=all_zero_distances)
106+
return OsrmRouteResponse(paths=legs, distances=distances, durations=durations, zero_distance=all_zero_distances)
89107

90108

91109
def query_routes(
92110
endpoint: str,
93111
routes: list[types.Route],
94-
) -> list[OsrRouteResponse]:
112+
) -> list[OsrmRouteResponse]:
95113
"""
96114
Queries multiple routes from the OSRM server.
97115
@@ -103,13 +121,17 @@ def query_routes(
103121

104122
# Query all routes
105123
reqs = [OsrmRouteRequest(positions=route.points) for route in routes]
106-
zero_distance_routes = 0
124+
zero_distance_routes, no_route_routes = 0, 0
107125
for r, req in enumerate(reqs):
108126
result = query_route(endpoint, req)
109127
routes[r].legs = result.paths
110128
routes[r].leg_distances = result.distances
111129
routes[r].leg_durations = result.durations
112130
if result.zero_distance:
113131
zero_distance_routes += 1
132+
if result.no_route:
133+
no_route_routes += 1
114134
if zero_distance_routes > 0:
115135
print(f"Warning: {zero_distance_routes} / {len(routes)} routes have zero distance according to OSRM")
136+
if no_route_routes > 0:
137+
print(f"Warning: {no_route_routes} / {len(routes)} routes could not be found by OSRM")

0 commit comments

Comments
 (0)