mod test_utils;
use geo::{algorithm::euclidean_distance::EuclideanDistance, Point};
use pelorus::matching::{MapMatcher, MapMatchingConfig};
use test_utils::{GridGenerator, TestAnalyzer, TestConfig};
#[test]
fn test_e2e_good_conditions() {
println!("π§ͺ Testing end-to-end map matching with good conditions...");
let config = TestConfig::good_conditions();
let generator = GridGenerator::new(config.clone());
println!(
"π Creating {}x{} Manhattan grid network...",
config.grid_size, config.grid_size
);
let network = generator.create_grid_network();
let _expected_segments = (config.grid_size + 1) * config.grid_size * 2; println!(" Created {} road segments", network.segment_count());
assert!(network.segment_count() > 0, "Network should have segments");
println!(
"π°οΈ Generating GPS trace from (0,0) to ({}, {})...",
config.grid_size * 100,
config.grid_size * 100
);
let (gps_trace, true_path) = generator.generate_gps_trace();
println!(" Generated {} GPS measurements", gps_trace.len());
assert!(
gps_trace.len() > 10,
"Should have sufficient GPS points for testing"
);
let map_config = MapMatchingConfig {
max_candidate_distance: 100.0, max_candidates_per_point: 15, gps_sigma: config.noise_std_dev,
break_time_threshold: 300.0, break_distance_threshold: 500.0, };
let matcher = MapMatcher::with_config(map_config);
println!("πΊοΈ Running map matching algorithm...");
let result = matcher.match_trace(&gps_trace, &network);
match result {
Ok(matched_traces) => {
println!(
" Successfully matched {} trace segments",
matched_traces.len()
);
let accuracy = TestAnalyzer::calculate_matching_accuracy(
&matched_traces,
&true_path,
&network,
);
let route_length = TestAnalyzer::calculate_route_length(&matched_traces);
let is_continuous = TestAnalyzer::check_continuity(&matched_traces);
let expected_route_length =
config.grid_size as f64 * config.block_size_meters * 2.0;
let length_error =
(route_length - expected_route_length).abs() / expected_route_length;
println!("π Results:");
println!(" - Matching accuracy: {:.1}%", accuracy * 100.0);
println!(
" - Route length: {:.1}m (expected: {:.1}m, error: {:.1}%)",
route_length,
expected_route_length,
length_error * 100.0
);
println!(" - Continuous trace: {}", is_continuous);
assert!(
accuracy >= 0.7,
"Accuracy should be at least 70% for good conditions, got {:.1}%",
accuracy * 100.0
);
assert!(
length_error <= 0.15,
"Route length error should be within 15%, got {:.1}%",
length_error * 100.0
);
if !is_continuous {
println!(" β οΈ Trace was split into {} segments (may be due to algorithm characteristics)", matched_traces.len());
}
println!("β
Good conditions test passed!");
}
Err(e) => {
println!("β Map matching failed: {:?}", e);
panic!("Map matching should succeed with good conditions");
}
}
}
#[test]
fn test_e2e_difficult_conditions() {
println!("π§ͺ Testing end-to-end map matching with difficult conditions...");
let config = TestConfig::difficult_conditions();
let generator = GridGenerator::new(config.clone());
println!(
"π Creating {}x{} Manhattan grid network...",
config.grid_size, config.grid_size
);
let network = generator.create_grid_network();
println!(
"π°οΈ Generating sparse GPS trace ({}s intervals, {}m noise)...",
config.sampling_interval, config.noise_std_dev
);
let (gps_trace, true_path) = generator.generate_gps_trace();
println!(" Generated {} GPS measurements", gps_trace.len());
let map_config = MapMatchingConfig {
max_candidate_distance: 100.0, max_candidates_per_point: 15, gps_sigma: config.noise_std_dev,
break_time_threshold: 60.0, break_distance_threshold: 300.0, };
let matcher = MapMatcher::with_config(map_config);
println!("πΊοΈ Running map matching algorithm...");
let result = matcher.match_trace(&gps_trace, &network);
match result {
Ok(matched_traces) => {
println!(
" Successfully matched {} trace segments",
matched_traces.len()
);
let accuracy = TestAnalyzer::calculate_matching_accuracy(
&matched_traces,
&true_path,
&network,
);
let route_length = TestAnalyzer::calculate_route_length(&matched_traces);
let expected_route_length =
config.grid_size as f64 * config.block_size_meters * 2.0;
let length_error = if expected_route_length > 0.0 {
(route_length - expected_route_length).abs() / expected_route_length
} else {
0.0
};
println!("π Results:");
println!(" - Matching accuracy: {:.1}%", accuracy * 100.0);
println!(
" - Route length: {:.1}m (expected: {:.1}m, error: {:.1}%)",
route_length,
expected_route_length,
length_error * 100.0
);
println!(" - Number of trace segments: {}", matched_traces.len());
assert!(
accuracy >= 0.3,
"Accuracy should be at least 30% for difficult conditions, got {:.1}%",
accuracy * 100.0
);
println!("β
Difficult conditions test passed!");
}
Err(e) => {
println!("β Map matching failed: {:?}", e);
println!("β οΈ Map matching failed with difficult conditions - this may be expected");
}
}
}
#[test]
fn test_grid_network_creation() {
println!("π§ͺ Testing grid network creation...");
let config = TestConfig::good_conditions();
let generator = GridGenerator::new(config.clone());
let network = generator.create_grid_network();
let _expected_segments = (config.grid_size + 1) * config.grid_size * 2;
println!(" Created {} segments", network.segment_count());
assert!(network.segment_count() > 0, "Network should have segments");
let center_point = Point::new(0.0005, 0.0005); let nearby_segments = network.query_segments_near(center_point, 0.001);
println!(
" Found {} segments near center point",
nearby_segments.len()
);
assert!(
nearby_segments.len() >= 2,
"Center point should find multiple segments"
);
println!("β
Grid network creation test passed!");
}
#[test]
fn test_gps_trace_generation() {
println!("π§ͺ Testing GPS trace generation...");
let config = TestConfig::good_conditions();
let generator = GridGenerator::new(config.clone());
let (gps_trace, true_path) = generator.generate_gps_trace();
assert_eq!(
gps_trace.len(),
true_path.len(),
"GPS trace and true path should have same length"
);
assert!(gps_trace.len() > 10, "Should generate sufficient points");
for i in 1..gps_trace.len() {
assert!(
gps_trace[i].timestamp > gps_trace[i - 1].timestamp,
"Timestamps should be increasing"
);
}
let start_point = &gps_trace[0].point;
let end_point = &gps_trace[gps_trace.len() - 1].point;
println!(" Start: ({:.6}, {:.6})", start_point.x(), start_point.y());
println!(" End: ({:.6}, {:.6})", end_point.x(), end_point.y());
let start_distance = start_point.euclidean_distance(&Point::new(0.0, 0.0));
let noise_tolerance = config.noise_std_dev / 111_000.0 * 3.0; assert!(
start_distance < noise_tolerance,
"Start point should be near origin within noise tolerance"
);
println!("β
GPS trace generation test passed!");
}