Skip to content

Commit ed18e76

Browse files
committed
Shortcuts consider routing restrictions on the main road too
Previously shortcuts only considered interior roads, starting from the border intersection, but we need to zoom out just a little bit more and consider *how* that traffic got to the intersection. Now routing additionally includes the `main` roads. In order to count only distinct internal trips, we filter out any routes that use the perimeter for anything other than starting/ending the trip. == Perf Oooph - much slower! It's still pretty fast overall, but I'm going to see if I can do anything to speed this up. shortcuts in bristol_east time: [1.6526 ms 1.6538 ms 1.6552 ms] change: [+130.08% +131.12% +132.13%] (p = 0.00 < 0.05) Performance has regressed. shortcuts in bristol_west time: [6.0927 ms 6.0966 ms 6.1012 ms] change: [+121.70% +122.09% +122.45%] (p = 0.00 < 0.05) Performance has regressed. shortcuts in strasbourg time: [2.3067 ms 2.3114 ms 2.3193 ms] change: [+88.807% +89.320% +89.947%] (p = 0.00 < 0.05) Performance has regressed.
1 parent 102a0be commit ed18e76

File tree

5 files changed

+44
-12
lines changed

5 files changed

+44
-12
lines changed

backend/src/neighbourhood.rs

+1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ impl Neighbourhood {
261261
self.neighbourhood
262262
.interior_roads
263263
.iter()
264+
.chain(self.neighbourhood.main_roads.iter())
264265
.map(|r| self.map.get_r(*r))
265266
}
266267

backend/src/shortcuts.rs

+40-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::collections::HashMap;
22

3-
use geo::{Euclidean, Length, LineString};
4-
use geojson::Feature;
5-
63
use crate::map_model::Direction;
74
use crate::route::Router;
85
use crate::{MapModel, Neighbourhood, RoadID};
6+
use geo::{Euclidean, Length, LineString};
7+
use geojson::Feature;
98

109
pub struct Shortcuts {
1110
pub paths: Vec<Path>,
@@ -27,25 +26,57 @@ impl Shortcuts {
2726
for start_i in &neighbourhood.border_intersections {
2827
let start_intersection = map.get_i(*start_i);
2928
for start_r in &start_intersection.roads {
30-
// It's not a "shortcut" unless it cuts through the interior.
31-
if !neighbourhood.interior_roads.contains(start_r) {
29+
// It's not a "shortcut" unless it starts outside the interior and cuts through the interior.
30+
if !neighbourhood.main_roads.contains(start_r) {
3231
continue;
3332
}
3433
for end_i in &neighbourhood.border_intersections {
3534
if start_i == end_i {
3635
continue;
3736
}
3837
let end_intersection = map.get_i(*end_i);
39-
for end_r in &end_intersection.roads {
40-
// It's not a "shortcut" unless it cuts through the interior.
41-
if !neighbourhood.interior_roads.contains(end_r) {
38+
'next_road: for end_r in &end_intersection.roads {
39+
// It's not a "shortcut" unless it ends outside the interior after cutting through.
40+
if !neighbourhood.main_roads.contains(end_r) {
4241
continue;
4342
}
43+
4444
let Some(route) = router.route_from_roads(*start_r, *end_r) else {
4545
continue;
4646
};
47+
4748
let mut shortcut_length = 0.0;
48-
for (r, _direction) in &route.steps {
49+
50+
let interior_steps = {
51+
let mut steps = route.steps.iter();
52+
let first_step = steps.next().expect("route can't be empty");
53+
let first_road = map.get_r(first_step.0);
54+
shortcut_length += Euclidean.length(&first_road.linestring);
55+
let mut steps_reversed = steps.rev();
56+
let Some(final_step) = steps_reversed.next() else {
57+
continue;
58+
};
59+
let final_road = map.get_r(final_step.0);
60+
shortcut_length += Euclidean.length(&final_road.linestring);
61+
62+
// re-reverse back to the original ordering, but without first and final steps
63+
steps_reversed.rev()
64+
};
65+
66+
for (r, _direction) in interior_steps {
67+
// For the purpose of counting unique shortcuts, only the first and
68+
// final steps should be on main roads.
69+
//
70+
// If we've left the interior, only the portion inside the interior counts
71+
// as distinct plausible shortcut.
72+
//
73+
// If a route leaves and re-enters the interior through another border
74+
// intersection, then that route will be counted as two distinct
75+
// shortcuts.
76+
if neighbourhood.main_roads.contains(&r) {
77+
break 'next_road;
78+
}
79+
4980
let road = map.get_r(*r);
5081
*count_per_road.entry(road.id).or_insert(0) += 1;
5182
shortcut_length += Euclidean.length(&road.linestring);

tests/output/bristol_east.geojson

+1-1
Large diffs are not rendered by default.

tests/output/bristol_west.geojson

+1-1
Large diffs are not rendered by default.

tests/output/strasbourg.geojson

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)