map updates
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user