Skip to main content

calculate_train_path

Function calculate_train_path 

Source
pub fn calculate_train_path(
    gnss_positions: &[GnssPosition],
    netelements: &[Netelement],
    netrelations: &[NetRelation],
    config: &PathConfig,
) -> Result<PathResult, ProjectionError>
Expand description

Calculate the most probable continuous train path through the network

Given GNSS positions, network netelements, netrelations defining connections, and configuration parameters, calculates the most likely continuous path the train traversed through the network.

§Arguments

  • gnss_positions - Ordered sequence of GNSS positions from train journey
  • netelements - Network segments (track) with LineString geometries
  • netrelations - Connections between netelements defining navigable paths
  • config - Path calculation configuration (distance/heading scales, cutoff distances, etc.)

§Returns

Ok(PathResult) containing:

  • path: The calculated train path as TrainPath (if calculation succeeded)
  • mode: Algorithm mode used (TopologyBased or FallbackIndependent)
  • projected_positions: GNSS positions with projected coordinates
  • warnings: Any non-fatal issues encountered during calculation

Err(ProjectionError) if:

  • No valid path exists through the network
  • Input data is invalid
  • Calculation fails for other reasons

§Algorithm

  1. Candidate Selection: Find candidate netelements within cutoff_distance for each GNSS position
  2. Emission Probability: Calculate per-candidate probability using distance and heading alignment
  3. Viterbi Decoding: Decode the globally optimal netelement sequence using log-space Viterbi
  4. Bridge Insertion: Insert intermediate netelements between non-adjacent Viterbi states
  5. Path Assembly: Return the assembled TrainPath with overall probability score

§Configuration Impact

  • distance_scale: Decay rate for distance probability (default 10.0m)
  • heading_scale: Decay rate for heading probability (default 2.0°)
  • cutoff_distance: Maximum distance for candidate selection (default 500.0m)
  • heading_cutoff: Maximum heading difference, rejects if exceeded (default 10.0°)
  • probability_threshold: Minimum probability for segment inclusion (default 0.02)
  • max_candidates: Maximum candidates to evaluate per GNSS position

§Example

use tp_lib_core::{calculate_train_path, PathConfig};
use tp_lib_core::models::{GnssPosition, Netelement, NetRelation};
use geo::LineString;
use chrono::Utc;

let gnss_positions = vec![
    GnssPosition::new(50.8503, 4.3517, Utc::now().into(), "EPSG:4326".to_string())?,
];

let netelements = vec![
    Netelement::new(
        "NE_001".to_string(),
        LineString::from(vec![(4.3500, 50.8500), (4.3530, 50.8530)]),
        "EPSG:4326".to_string(),
    )?,
];

let netrelations = vec![];
let config = PathConfig::default();

let result = calculate_train_path(&gnss_positions, &netelements, &netrelations, &config)?;
println!("Path: {:?}", result.path);