Skip to contents

osmnxr 0.1.6

  • Credit. osmnxr is a port of OSMnx by Geoff Boeing, and earlier releases understated that by calling it “inspired by” OSMnx. The title, description, README, website and package help now say so; the OSMnx MIT copyright notice ships in inst/COPYRIGHTS; citation("osmnxr") gives Boeing (2025) doi:10.1111/gean.70009 first; and the documentation states that the port was AI-assisted and that the package is not affiliated with the OSMnx project.

A parity pass against what OSMnx gained in 2025–2026 (releases 2.0.1–2.1.1), plus the OSMnx 2.0 features the simplification/consolidation step was missing. The Rust core is now a crate of its own.

  • The graph algorithms (CSR graph, Dijkstra, Yen, Pareto/constrained routing, TSP, centrality, simplification, snapping) moved unchanged to the dependency-free crate osmnxr-core (https://strategicprojects.github.io/osmnxr-core/), which the package pins exactly and bundles in src/rust/vendor.tar.xz; src/rust/src/lib.rs keeps only the extendr wrappers. Results do not change. Building from source needs Rust 1.81 or later.

  • The Overpass network filters now mirror OSMnx 2.1’s tag for tag, replacing the simplified highway-only regexes used so far. Downloads gain the negative filters (area=yes, access=private, motor_vehicle=no, foot=no, bicycle=no, service-road subtypes, ways tagged rest_area/services, and walk ways whose sidewalk is mapped as a separate way), and two network types join drive/walk/bike/all: drive_service (drivable including service roads) and all_public. Note two behaviour changes: "drive" no longer includes service roads (use "drive_service"), and "all" now means every in-use way including private access rather than literally every highway value.

  • ox_simplify() now preserves every edge attribute column (a merged edge takes its first segment’s value) instead of keeping only highway and name, and gained edge_attr_aggs (as in OSMnx 2): a named list of functions combining per-segment values along each merged chain, e.g. list(travel_time = sum, speed_kph = mean). By default travel_time and penalty are summed when present, so pre-computed routing weights survive simplification instead of being dropped.

  • ox_consolidate_intersections() accepts a per-node tolerance (one merge radius per node, as in OSMnx 2: nodes merge when buffers of tolerance/2 overlap), validates the tolerance, and now warns when asked to consolidate an already-consolidated graph — it proceeds, since re-clustering with a larger tolerance is well-defined here, but the double run is made visible.

  • New ox_validate() checks that a graph meets the package’s structural expectations — sf types, complete and unique node ids, resolvable u/v, a usable length, one CRS, and edge geometries that actually run from their u node to their v node — reporting every problem found in one pass (OSMnx gained validation helpers in 2.1.0). Handy after building a layer by hand for ox_blend()/ox_union().

osmnxr 0.1.5

  • New ox_blend() blends point locations — or a whole second graph — into a street network (#6, requested by @talegari), the osmnxr counterpart of sfnetworks::st_network_blend(): each point is snapped onto its nearest edge (grid-indexed planar search in the Rust core) and the edge is split there, in both directions of a two-way street, turning the location into a routable node. Attributes are preserved (length recomputed; travel_time / penalty rescaled proportionally), points beyond tolerance are skipped with a warning, and meta$blend maps every input to its node. Given a second osm_graph, the three-step recipe from the issue is applied: blend its nodes in, stack the graphs with ox_union(), and add connector edges between each snapped pair — one routable multimodal network.

  • ox_blend() gained finer control from @talegari’s field test on the Delhi road + metro networks (#6): meta$blend now also records u / v, the endpoints of the edge each point snapped onto; snap_nodes flags which points (or y nodes) may snap (station gates yes, platforms no); snap_edges flags which edges of g may receive them (keep off limited-access flyovers); connector_node_attrs copies y node attributes — say, a per-station access time — onto the connector edges; and reusing a g osmid in y at different coordinates is now an error with a renumbering hint, instead of a silently corrupting first-wins merge.

  • New ox_route_shortest() rounds out the ox_route_* family (#5 feedback, @talegari): the sf interface to shortest-path routing, returning cost, node path and merged street geometry per route, with k > 1 enumerating loopless alternatives (Yen) — one naming scheme and one return shape across ox_route_shortest(), ox_route_constrained(), ox_route_pareto() and ox_route_tsp(). ox_shortest_path() and ox_k_shortest_paths() remain as the lighter node-sequence variants.

  • Repeated routing calls on the same graph are much faster (#5 feedback, @talegari): the structural edge index that every router marshals for the Rust core (the dominant per-call cost on metro-sized graphs) is now cached for the session, content-addressed by the graph’s node ids and edge endpoints — so copies hit, edits miss, and nothing goes stale. On the NCR Delhi network (2.1M directed edges) a warm ox_route_constrained() call drops from ~0.7 s to the Rust solve time itself. ox_clear_cache() also clears this cache. The Dijkstra/Yen solvers additionally return the edges they traversed, so ox_route_shortest() and ox_route_tsp() draw exact geometry across parallel edges (previously ox_route_tsp() drew the minimum-weight twin).

  • New preference-aware routing (#5, requested by @talegari): ox_route_constrained() finds the exact minimum-cost route whose consumption of a second edge criterion stays within a budget (e.g. “the shortest route using at most 500 m of residential streets”), and ox_route_pareto() enumerates the full Pareto front of cost-vs-preference trade-offs. Both run on a bicriteria label-setting solver (Martins’ algorithm) with dominance pruning and reverse-Dijkstra bounds in the Rust core — exact, deterministic, one-way streets respected. The new helper ox_add_edge_penalties() builds the penalty/resource edge column from OSM highway classes; added onto the routing weight it also covers simple scalarized (“soft preference”) routing through ox_shortest_path().

  • ox_route_constrained(method = "lagrangian") adds a Lagrangian-relaxation solver (the LARAC algorithm) beside the exact one: the budget constraint is dualized so each iteration is a plain Dijkstra on weight + lambda * resource, which scales to networks where the exact front grows too large. The route returned is always feasible and carries a proven lower_bound on the optimal cost (cost == lower_bound certifies optimality; a message reports any duality gap). The exact method now also reports lower_bound, always equal to cost (#5).

  • Route geometry reconstruction is dramatically faster on large graphs. The bicriteria routers now receive the traversed edge indices straight from the Rust solvers, so no parallel-edge lookup is needed at all — and the geometry is exact even across parallel edges that differ in cost or resource (previously the minimum-weight twin was drawn). On the NCR Delhi drive network (1.0M nodes / 2.1M directed edges) an ox_route_constrained() query runs in ~0.7 s and a 9-route ox_route_pareto() front in ~1.5 s, down from ~16 s and ~140 s. For ox_route_tsp(), the parallel-edge lookup is now built once per call instead of once per leg (and sorts numerically instead of by string key).

osmnxr 0.1.4

  • New ox_route_tsp() solves a travelling-salesman route through a set of stops over the street network, in the spirit of sfnetworks::st_network_travel(): the asymmetric network-distance matrix (one-way streets respected) is computed in the Rust core, the visiting order is solved there too with an iterated local search (or-opt + swap + 2-opt descent restarted from double-bridge perturbations, deterministic), and each leg is returned as an sf row with its cost, node path and street geometry. Supports closed tours (end = start, the default), open routes (end = NULL) and a pinned final stop. Benchmarked against TSP::solve_TSP() (the backend of sfnetworks::st_network_travel()) on identical cost matrices over the bundled real networks, it matched or beat it in all 80 random instances tried (8–50 stops), by ~1% on average at 8 stops up to ~10% at 50 (#4, requested by @talegari).

osmnxr 0.1.3

  • ox_graph_from_*() is dramatically faster on large areas: building the graph from the Overpass response was quadratic in the number of edges (it never finished on a metro-sized bbox) and is now vectorised — a response with 600,000 nodes / 1 million directed edges parses in ~15 s (#3, reported by @talegari).

  • Overpass and Nominatim requests now retry on HTTP 500, 502 and 504 (and on connection failures) in addition to httr2’s default 429/503, with exponential backoff. The number of attempts remains configurable via ox_settings(max_tries = ) (#2, reported by @talegari).

osmnxr 0.1.2

CRAN release: 2026-10-19

  • New ox_union() combines two or more osm_graph objects into one: node and edge tables are stacked, nodes sharing an osmid are merged and edges duplicated across graphs are dropped (dedupe_edges = FALSE keeps them). Attribute columns present in one graph but not another are filled with NA. Designed for multimodal networks — union a street graph with a hand-built layer (e.g. metro) whose transfer edges reference street-node osmids, then route across both (#1, requested by @talegari).

osmnxr 0.1.1

CRAN release: 2026-07-05

  • Fix installation on Windows (R-devel). The rextendr 0.5.0 Makevars templates ran an unnecessary install-time cargo run --bin document step that failed on Windows (os error 193 while running a build script). The extendr wrappers are pre-generated and shipped, so installation only needs cargo build --lib; the document step has been removed from Makevars.in / Makevars.win.in.

osmnxr 0.1.0

First public release of OSMnx for R.