Expand description
A Rust library to accurately project an ordered list of stops onto a route line. This version uses a high-performance greedy algorithm with single-level backtracking to robustly handle complex route overlaps.
§Algorithm Overview
-
Anchoring & Spatial Index: The first stop is fixed to the start of the route (
distance = 0), and the last stop is fixed to the end. An R-tree is built from the route’s line segments for fast geometric lookups. -
Greedy Forward Search: For each intermediate stop, an adaptive search finds the most plausible forward projection. It does this by creating a small pool of valid forward candidates from the nearest segments and then selecting the one with the best geographic fit (lowest projection error).
-
Backtracking on Failure: If projecting
Stop Nfails (no valid forward candidates are found), the algorithm assumes the greedy choice forStop N-1was incorrect (e.g., snapped to an early part of a large loop). It then: a. Backtracks toStop N-1. b. Re-runs the search forStop N-1, explicitly excluding the previous projection. c. With a new, corrected projection forStop N-1, it retries projectingStop N.
§Example Usage
use route_snapper::{project_stops, Stop};
use geo_types::{Coord, LineString};
fn main() {
let route_line = LineString::from(vec![
Coord { x: 0.0, y: 0.0 }, // Start (matches Stop "A")
Coord { x: 100.0, y: 0.0 },
Coord { x: 200.0, y: 0.0 }, // End of cul-de-sac
Coord { x: 100.0, y: 0.0 },
Coord { x: 0.0, y: 0.0 }, // End (matches Stop "D")
]);
let stops = vec![
Stop { id: "A".to_string(), location: Coord { x: 0.0, y: 1.0 } }, // First stop
Stop { id: "B".to_string(), location: Coord { x: 99.0, y: 2.0 } }, // Intermediate
Stop { id: "C".to_string(), location: Coord { x: 101.0, y: -2.0 } }, // Intermediate (on overlap)
Stop { id: "D".to_string(), location: Coord { x: 0.0, y: -1.0 } }, // Last stop
];
let results = project_stops(&route_line, &stops, None).unwrap();
assert!((results[0].distance_along_route - 0.0).abs() < 1e-9); // First stop anchored
assert!((results[1].distance_along_route - 99.0).abs() < 1e-9); // Snapped correctly
assert!((results[2].distance_along_route - 299.0).abs() < 1e-9); // Snapped correctly on return trip
assert!((results[3].distance_along_route - 400.0).abs() < 1e-9); // Last stop anchored
}Structs§
- Projected
Stop - The output struct representing a stop’s successful projection onto the route.
- Projection
Config - A configuration struct for the projection algorithm.
- Stop
- Represents a single bus stop with a unique identifier and location.
Enums§
- Projection
Error - Custom error types for the library.
Functions§
- project_
stops - The main function of the library.