nvdb2osmr

WARNING (in case you did not notice the experimental badge above): this is highly experimental and can break at any moment until further notice. This is still work in progress and not yet ready for production use. Use at your own risk.

The goal of nvdb2osmr is to convert Swedish NVDB (Nationell VägDataBas) road network data into OpenStreetMap (OSM) format. It provides high-performance tools using DuckDB for spatial I/O and Rust for topological simplification, enabling efficient processing of large road network datasets.

This R package is based on the nvdb2osm Python script by NKAmapper, licensed under CC0-1.0.

Data Source

To use this package, you need to obtain NVDB data from Lastkajen at Trafikverket:

  1. Register (free) at Lastkajen
  2. Choose the Homogeniserad format for your municipality/county
  3. Check for all attributes
  4. Download the GeoDB folder when ready

Features

Supported OSM Tags

The package converts NVDB attributes to standard OSM tags including:

Prerequisites

This package requires Rust (to compile the core algorithm) and the Osmium tool (to merge and sort output files).

1. Rust

All Platforms

Install Rust from rustup.rs

Linux/macOS:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Windows: After installing Rust from rustup.rs, run this additional command:

rustup default stable-x86_64-pc-windows-gnu

Alternatively, on Linux (Ubuntu/Debian):

sudo apt install cargo rustc

2. Osmium Tool

Required for merging municipality PBF chunks into a single file.

Installation

You can install the development version of nvdb2osmr from GitHub with:

# install.packages("pak")
# pak::pak("e-kotov/nvdb2osmr")
install.packages("nvdb2osmr", repos = c('https://e-kotov.r-universe.dev', 'https://cloud.r-project.org'))

Example

Convert a municipality from NVDB FileGDB to OSM PBF:

library(nvdb2osmr)

# Convert a single municipality (e.g., Umeå = 2480)
nvdb_to_pbf(
  input_path = "path/to/nvdb_data.gdb",
  output_pbf = "output/umea.osm.pbf",
  municipality_codes = "2480"
)

Process multiple municipalities in parallel:

# Start mirai daemons before calling nvdb_to_pbf()
mirai::daemons(4)
on.exit(mirai::daemons(0), add = TRUE)

# Process several municipalities in parallel
nvdb_to_pbf(
  input_path = "path/to/nvdb_data.gdb",
  output_pbf = "output/region.osm.pbf",
  municipality_codes = c("2480", "2580", "2581")  # Umeå, Skellefteå, Piteå
)

Process all municipalities in a dataset (e.g., full Sweden):

# Configure daemons based on available cores
mirai::daemons(max(1L, parallel::detectCores() - 1L))
on.exit(mirai::daemons(0), add = TRUE)

# Process all municipalities automatically
# For large datasets, GeoParquet optimization is applied automatically
nvdb_to_pbf(
  input_path = "path/to/sweden_nvdb.gdb",
  output_pbf = "output/sweden.osm.pbf"
)

Advanced options:

# Force GeoParquet conversion for faster subsequent runs
# Enable pre-splitting for better load balancing on very large datasets
nvdb_to_pbf(
  input_path = "path/to/nvdb_data.gdb",
  output_pbf = "output/sweden.osm.pbf",
  use_geoparquet = TRUE,   # Convert to GeoParquet (10x faster for large files)
  presplit = TRUE,         # Pre-split by municipality for better parallelization
  max_retries = 3          # Retry failed municipalities
)

Split Processing and Global Node Prepass

When you process by split_by = "municipality" or split_by = "county", the converter requires a global endpoint-node dictionary to keep node IDs consistent across split boundaries.

This prevents split-induced graph disconnections caused by duplicated boundary endpoint nodes.

nvdb_to_pbf(
  input_path = "path/to/sweden_nvdb.gdb",
  output_pbf = "output/sweden.osm.pbf",
  split_by = "municipality",
  global_node_prepass = "auto"
)

Failure policy when prepass is active: all split chunks must succeed. If any area fails, the run aborts and no partial merged output is kept.