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 journeynetelements- Network segments (track) with LineString geometriesnetrelations- Connections between netelements defining navigable pathsconfig- 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 coordinateswarnings: 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
- Candidate Selection: Find candidate netelements within cutoff_distance for each GNSS position
- Emission Probability: Calculate per-candidate probability using distance and heading alignment
- Viterbi Decoding: Decode the globally optimal netelement sequence using log-space Viterbi
- Bridge Insertion: Insert intermediate netelements between non-adjacent Viterbi states
- 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);