map updates

This commit is contained in:
2026-07-08 15:06:57 +05:30
parent 5c129bbdfe
commit 78b1666402
9 changed files with 457 additions and 71 deletions

View File

@@ -103,6 +103,22 @@ pub fn track_value(track: &[Pt]) -> Value {
)
}
/// Average + maximum speed over a track (m/s), from the full-resolution samples.
/// Max is measured over single hops (dt clamped ≥ 0.5 s so duplicate timestamps
/// can't fabricate teleports). None when the track has no elapsed time.
pub fn speed_stats(track: &[Pt]) -> (Option<f64>, Option<f64>) {
if track.len() < 2 {
return (None, None);
}
let elapsed = track.last().unwrap()[2] - track[0][2];
let avg = (elapsed > 0.0).then(|| polyline_len_m(track) / elapsed);
let max = track
.windows(2)
.map(|w| dist_m(w[0][0], w[0][1], w[1][0], w[1][1]) / (w[1][2] - w[0][2]).max(0.5))
.fold(None::<f64>, |acc, v| Some(acc.map_or(v, |a| a.max(v))));
(avg, max)
}
/// Cap a track at `max` points (uniform stride, always keeping the last point).
pub fn downsample(track: Vec<Pt>, max: usize) -> Vec<Pt> {
if track.len() <= max || max < 2 {
@@ -851,6 +867,21 @@ mod tests {
assert_eq!(d.last(), t.last());
}
#[test]
fn speed_stats_measures_avg_and_max() {
// ~11.13 m per second for 60 s → avg ≈ max ≈ 11.1 m/s (40 km/h).
let t = straight(60);
let (avg, max) = speed_stats(&t);
assert!((avg.unwrap() - 11.13).abs() < 0.1, "{avg:?}");
assert!((max.unwrap() - 11.13).abs() < 0.1, "{max:?}");
// One fast hop dominates max but barely moves avg.
let mut t2 = straight(60);
t2[30][1] += 0.0002; // extra ~22 m in that second
let (avg2, max2) = speed_stats(&t2);
assert!(max2.unwrap() > 25.0, "{max2:?}");
assert!(avg2.unwrap() < 13.0, "{avg2:?}");
}
#[test]
fn stitch_planning_rules() {
// Healthy 1 Hz rollover (1 s gap) → nothing missing.