Getting Started
Getting Started with solverforge-maps
This guide covers the standard solverforge-maps workflow:
- validate input coordinates
- derive a bounding box that covers the relevant area
- load a road network from cache or Overpass
- compute a travel-time matrix
- optionally compute a route for visualization or debugging
Prerequisites
- Rust stable toolchain
- An async runtime such as Tokio
- Internet access the first time a new road network is fetched
Add the Dependency
[dependencies]
solverforge-maps = "2"
tokio = { version = "1", features = ["full"] }
Step 1: Start with Validated Coordinates
Coord::try_new is the right choice for user input, CSV imports, and API payloads because it rejects invalid latitude and longitude values.
use solverforge_maps::Coord;
let depot = Coord::try_new(39.9526, -75.1652)?;
let customer_a = Coord::try_new(39.9610, -75.1700)?;
let customer_b = Coord::try_new(39.9440, -75.1500)?;
let locations = vec![depot, customer_a, customer_b];
Step 2: Build a Routing Bounding Box
Use BoundingBox::from_coords and then expand it for realistic road detours.
use solverforge_maps::BoundingBox;
let bbox = BoundingBox::from_coords(&locations).expand_for_routing(&locations);
That expansion matters because road routes rarely travel in a straight line. A tight bounding box can clip the roads needed for a valid path.
Step 3: Load or Fetch the Road Network
use solverforge_maps::{NetworkConfig, RoadNetwork};
let config = NetworkConfig::default();
let network = RoadNetwork::load_or_fetch(&bbox, &config, None).await?;
load_or_fetch gives you the normal production behavior:
- reuse the in-memory cache when possible
- reuse the file cache when the region was fetched before
- fall back to the Overpass API only when necessary
Step 4: Compute the Travel-Time Matrix
let matrix = network.compute_matrix(&locations, None).await;
println!("Matrix size: {}", matrix.size());
This matrix is the bridge between geospatial data and optimization. A VRP solver can use it as the cost model for sequencing stops, estimating arrival times, and comparing alternative route plans.
Step 5: Route Individual Pairs
let route = network.route(locations[0], locations[1])?;
println!("Duration: {} seconds", route.duration_seconds);
println!("Geometry points: {}", route.geometry.len());
route() snaps both endpoints to the nearest graph nodes before routing. That is a good default for travel-time analysis, but it can produce geometries that start and end at nearby intersections instead of the exact stop positions.
For frontend rendering where the route should stay on the containing road segments, use edge snapping:
let from = network.snap_to_edge(locations[0])?;
let to = network.snap_to_edge(locations[1])?;
let route = network.route_edge_snapped(&from, &to)?;
Full Example
use solverforge_maps::{BoundingBox, Coord, NetworkConfig, RoadNetwork, RoutingResult};
#[tokio::main]
async fn main() -> RoutingResult<()> {
let locations = vec![
Coord::try_new(39.9526, -75.1652)?,
Coord::try_new(39.9610, -75.1700)?,
Coord::try_new(39.9440, -75.1500)?,
];
let bbox = BoundingBox::from_coords(&locations).expand_for_routing(&locations);
let config = NetworkConfig::default();
let network = RoadNetwork::load_or_fetch(&bbox, &config, None).await?;
let matrix = network.compute_matrix(&locations, None).await;
let route = network.route(locations[0], locations[1])?;
println!("Matrix size: {}", matrix.size());
println!("Route duration: {} seconds", route.duration_seconds);
Ok(())
}
Common Next Steps
After the first matrix is working, most applications move on to one or more of these tasks:
- inspect route geometry in a frontend map
- check cache hit rates for repeated workloads
- compute full matrices for solver input
- tune
NetworkConfigfor production environments
Read Core Types, Routing & Matrices, and Caching & Operations for those topics.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.