TP-Lib: Train Positioning Library
Status: Under construction
Train positioning library excels in post-processing the GNSS positions of your measurement train to achieve an unambiguous network location. This library is your map matching assistant specifically for railway.
Features
- π High Performance: R-tree spatial indexing for O(log n) nearest-track search
- π Accurate Projection: Haversine distance and geodesic calculations with geo-rs
- π€οΈ Train Path Calculation: Probabilistic path calculation through rail networks using topology
- πΊοΈ Interactive Path Review: Browser-based map webapp to visually review and edit calculated paths before projection
- π CRS Aware: Explicit coordinate reference system handling (EPSG codes)
- β° Timezone Support: RFC3339 timestamps with explicit timezone offsets; timezone-less ISO 8601 datetimes assumed UTC
- π Multiple Formats: CSV and GeoJSON input/output
- π§ͺ Well Tested: 460 comprehensive tests (all passing) - unit, integration, contract, CLI, and doctests
- β‘ Production Ready: Full CLI interface with validation and error handling
Train Path Calculation
The library supports continuous train path calculation using network topology (netrelations) to determine the most probable route a train took through the railway network.
How It Works
- Candidate Selection: Find candidate track segments within cutoff distance of each GNSS position
- Emission Probability: Calculate per-position probability using exponential decay of distance and heading alignment
- Viterbi Decoding: Decode the globally optimal netelement sequence using a log-space Viterbi algorithm (HMM map matching, Newson & Krumm 2009). Transition probabilities are derived from shortest-path vs. great-circle distance through the topology graph. Bridge netelements are inserted automatically for path continuity.
CLI Commands
# Default: Calculate path AND project coordinates onto it
# Calculate path only (export path segments without projection)
# Simple projection (legacy mode, no path calculation)
# Use pre-calculated path for projection
# Review calculated path in browser before projection (integrated mode)
# Launch standalone webapp to review/edit a path file
Debug Output
Pass --debug to write intermediate HMM calculation results as GeoJSON files to a debug/ subdirectory next to the output file.
See DEBUG.md for a full description of the debug output files, their properties, and a typical debugging workflow.
Algorithm Parameters
| Parameter | Default | Description |
|---|---|---|
--distance-scale |
10.0 | Distance decay scale (meters) |
--heading-scale |
2.0 | Heading decay scale (degrees) |
--cutoff-distance |
500.0 | Max distance for candidate selection (meters) |
--heading-cutoff |
10.0 | Max heading difference to accept (degrees) |
--probability-threshold |
0.02 | Minimum emission probability for candidate inclusion |
--max-candidates |
3 | Max candidates per GNSS position |
--resampling-distance |
None | Optional GNSS resampling distance (meters) |
Performance
- Benchmark: 1000 positions Γ 50 netelements in ~900ΞΌs (target was <10s)
- Scalability: Sub-linear scaling with R-tree spatial indexing
- Memory: Handles 10,000+ positions efficiently
Train Path Review Webapp
The library ships a companion browser-based map webapp (tp-webapp) that lets you visually inspect and edit a calculated train path before using it for projection. No npm, no Node.js, no frontend build step required β the web assets are embedded in the binary at compile time using rust-embed.
Modes
| Mode | Command | Use case |
|---|---|---|
| Standalone | tp-cli webapp |
Review/edit an existing path file; save result to disk; server stays alive |
| Integrated | tp-cli β¦ --review |
Pause the projection pipeline after path calculation; confirm or abort in the browser |
What You Can Do in the Browser
- View all network segments on a Leaflet map (OpenStreetMap basemap, toggleable)
- Path segments are highlighted with a colour-coded confidence scale
- Add a netelement to the path by clicking it on the map β snapped to the correct topological position
- Remove a path segment by clicking it β segment reverts to the default style
- Sidebar shows an ordered list of segments with probability scores
- Dark mode toggle (auto-activates from OS
prefers-color-scheme) - Close Tab button for clean exit after the server shuts down
Standalone Usage
A browser opens at http://127.0.0.1:8765. Click Save to write the reviewed path; the server stays alive for further edits. Press Ctrl+C when done.
The saved file is accepted directly by --train-path:
Integrated Usage
- CLI calculates the train path
- Browser opens automatically β review and edit the path
- Click Confirm β path artifact saved as
result-path.csv; projection continues - Click Abort β CLI exits with non-zero code
Build Without Web Server
Project Structure
tp-lib/ # Rust workspace root
βββ tp-core/ # Core Rust library
β βββ src/
β β βββ models/ # Data models (GnssPosition, Netelement, ProjectedPosition, PathOrigin)
β β βββ projection/ # Projection algorithms (geom, spatial indexing)
β β βββ path/ # Train path calculation (candidate, probability, graph, viterbi)
β β βββ io/ # Input/output (CSV, GeoJSON, Arrow)
β β βββ crs/ # Coordinate reference system transformations
β β βββ temporal/ # Timezone handling utilities
β β βββ errors.rs # Error types
β βββ tests/
β β βββ unit/ # Unit tests
β β βββ integration/ # Integration tests
β βββ benches/ # Performance benchmarks
βββ tp-cli/ # Command-line interface
βββ tp-webapp/ # Interactive path review web server (axum + Leaflet.js)
βββ tp-py/ # Python bindings (PyO3)
βββ tp-net/ # .NET bindings (csbindgen + System.Text.Json)
Quick Start
Prerequisites
- Rust 1.91.1+ (install from rustup.rs)
- Python 3.12+ (for Python bindings)
Build from Source
# Clone repository
# Build all crates
# Run tests
# Run benchmarks
Docker Usage
Production Deployment
Use Docker to run the CLI without installing Rust:
# Build production image
# Run with mounted data directory
# Or use docker-compose
Running Tests in Docker
Run the complete test suite including CRS transformation tests:
# Using docker-compose (recommended)
# Or build and run test image directly
# Run specific tests
# Run only CRS transformation tests
# Interactive shell for debugging
Why Docker for tests?
- Complete test coverage: Runs all tests including CRS transformation tests
- Consistent environment: Same Rust version across all machines
- No local setup needed: No need to install Rust toolchain locally
- CI/CD ready: Use
Dockerfile.testin GitHub Actions or other CI systems
Usage Examples
# CLI usage - CSV input/output
# GeoJSON output with custom warning threshold
# Custom CSV column names
Library Usage
use ;
use ;
Implementation Notes
Performance
- Target: < 10 seconds for 1000 GNSS positions Γ 50 netelements (SC-001)
- Memory: Handles 10,000+ positions without exhaustion (SC-006)
- Accuracy: 95% of positions within 2m projection distance (GPS quality dependent)
- R-tree Complexity: O(log n) nearest-neighbor search
Input Data Requirements
GNSS CSV:
latitude,longitude,timestamp,altitude,hdop
50.8503,4.3517,2025-12-09T14:30:00+01:00,100.0,2.0
- RFC3339 timestamps with timezone (e.g.
2025-12-09T14:30:00+01:00or2025-12-09T14:30:00Z); timezone-less ISO 8601 datetimes (e.g.2025-12-09T14:30:00) are accepted and assumed UTC - CRS must be specified via
--crsflag - Column names configurable with
--lat-col,--lon-col,--time-col
Railway Network GeoJSON:
- LineString geometries (track centerlines)
- Unique
idproperty per netelement crsproperty with EPSG code
Troubleshooting
"Large projection distance" warnings:**
Indicates GNSS position is far from nearest track (> threshold). Possible causes:
- GPS inaccuracy or poor signal quality
- Train on parallel track not in network
- Missing netelement in railway network
- CRS mismatch between GNSS and network
- Track geometry outdated or incorrect
Adjust threshold with --warning-threshold flag or investigate data quality.
"No Python 3.x interpreter found" build error:
Building with default features requires Python for PyO3 bindings. Disable with:
Or install Python 3.12+ and ensure it's in your PATH.
Known Issues
- Windows Build Dependencies: Requires MSVC toolchain or mingw-w64 for some native dependencies
- Python Bindings: Requires Python 3.12+ installed (excluded from tp-py crate builds by default)
CRS Transformations
TP-Lib uses proj4rs, a pure Rust implementation of PROJ.4, for coordinate reference system transformations. This eliminates system dependencies and enables cross-platform compatibility.
Key Features:
- Pure Rust: No external C libraries required (libproj, sqlite3, etc.)
- Zero system dependencies: Works on Windows, Linux, macOS without installation
- EPSG support: Uses
crs-definitionscrate for EPSG code lookup - WASM compatible: Can be used in browser environments
- Always enabled: CRS transformations are available by default
Supported Transformations:
TP-Lib has been tested with Belgian railway coordinate systems:
- EPSG:4326 (WGS84) β EPSG:31370 (Belgian Lambert 72)
- EPSG:4326 (WGS84) β EPSG:3812 (Belgian Lambert 2008)
- Any EPSG codes supported by crs-definitions
Usage:
use CrsTransformer;
use Point;
// Create transformer (EPSG codes or PROJ strings)
let transformer = new?;
// Transform point (automatic degree/radian conversion)
let wgs84_point = new;
let lambert_point = transformer.transform?;
Technical Details:
- proj4rs automatically handles radian/degree conversions for geographic CRS
- EPSG codes are resolved to PROJ strings using the crs-definitions crate
- Custom PROJ strings can be used directly instead of EPSG codes
- Transformation accuracy matches PROJ for standard 2D transformations
Limitations:
- proj4rs implements PROJ.4 API (2D transformations only)
- No 3D/4D or orthometric transformations
- Grid shift support is experimental
- For complex geodetic requirements, consider using PROJ directly
Documentation
API Documentation
Online: https://matdata-eu.github.io/tp-lib/
The documentation is automatically built and deployed on every push to main. It includes:
- tp-core: Core library API with examples
- tp-cli: Command-line interface documentation
- tp-py: Python bindings API reference
- tp-net: .NET bindings API reference
Build locally:
# Generate documentation for all workspace crates
# Open in browser (on Windows)
# Open in browser (on Linux/macOS)
Specification Documents
Feature 001 β GNSS Projection
Feature 002 β Train Path Calculation
Feature 003 β Train Path Review Webapp
- Feature Specification
- Implementation Plan
- Data Model
- REST API Contract
- CLI Contract
- Quickstart
- Tasks
CI/CD & Workflows
This project uses automated workflows for continuous integration and deployment:
- π Continuous Integration: Automated testing, linting, and security checks on every push
- π¦ crates.io Publishing: Automatic release to Rust package registry
- π PyPI Publishing: Automatic release to Python package index
- π Documentation Deployment: Auto-deployed to GitHub Pages
See CI/CD Workflows Documentation for details on:
- Build and test automation
- Release process and version management
- Security and license validation
- Publishing to crates.io and PyPI
- Documentation deployment
Constitution Compliance
This project follows the TP-Lib Constitution v1.1.0 principles:
- β I. Library-First: Single unified library with quality external dependencies
- β II. CLI Mandatory: Command-line interface for all functionality
- β III. High Performance: Apache Arrow, R-tree spatial indexing
- β IV. TDD: Test-driven development with FIRST TEST validation
- β V. Full Coverage: Comprehensive test suite (unit, integration, property-based)
- β VI. Timezone Awareness: DateTime for all timestamps
- β VII. CRS Explicit: All coordinates include CRS specification
- β VIII. Error Handling: Typed errors with thiserror, fail-fast validation
- β IX. Data Provenance: Preserve original GNSS data, audit logging
- β X. Integration Flexibility: Rust API + CLI + Python bindings + .NET bindings
Contributing
This project follows strict TDD workflow:
- Write test first (RED)
- Implement minimum code to pass (GREEN)
- Refactor while keeping tests green
See CONTRIBUTING.md for guidelines.
License
Apache License 2.0 - See LICENSE for details
Contact
TP-Lib Contributors - GitHub Issues