mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-09 23:26:31 +00:00
handle corrupt time data
This commit is contained in:
1 parent
f0851086c0
commit
e8c4eb92f9
2 files changed
+47
-3
No files matched your search
@@ -283,13 +283,18 @@ pub struct GlobalStatistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalStatistics {
|
impl GlobalStatistics {
|
||||||
|
/// Average speed over the total time, unknown if that is not a positive duration (for
|
||||||
|
/// example a range with a single timestamp, or timestamps going backwards).
|
||||||
pub fn total_speed(&self) -> Option<f64> {
|
pub fn total_speed(&self) -> Option<f64> {
|
||||||
self.total_time.map(|t| speed(self.total_distance, t))
|
self.total_time
|
||||||
|
.filter(|t| *t > 0)
|
||||||
|
.map(|t| speed(self.total_distance, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Average speed over the moving time, unknown if there is no moving time.
|
||||||
pub fn moving_speed(&self) -> Option<f64> {
|
pub fn moving_speed(&self) -> Option<f64> {
|
||||||
self.moving_distance
|
self.moving_distance
|
||||||
.zip(self.moving_time)
|
.zip(self.moving_time.filter(|t| *t > 0))
|
||||||
.map(|(d, t)| speed(d, t))
|
.map(|(d, t)| speed(d, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,8 @@ impl StatisticsBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let delta = |values: &[f64]| values[end] - values[start];
|
let delta = |values: &[f64]| values[end] - values[start];
|
||||||
let delta_time = |values: &[i64]| values[end] - values[start];
|
// the total time is the span of the timestamps, which is negative where they go backwards
|
||||||
|
let delta_time = |values: &[i64]| (values[end] - values[start]).max(0);
|
||||||
let time = |i: usize| {
|
let time = |i: usize| {
|
||||||
let time = self.time.as_ref()?[i];
|
let time = self.time.as_ref()?[i];
|
||||||
(time != NO_TIME).then_some(time)
|
(time != NO_TIME).then_some(time)
|
||||||
@@ -559,6 +560,44 @@ mod tests {
|
|||||||
assert_eq!(slice.end_time, global.end_time);
|
assert_eq!(slice.end_time, global.end_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slices_of_corrupt_timestamps_are_never_negative_nor_infinite() {
|
||||||
|
let (mut segment, _) = computed("data/with_time.gpx");
|
||||||
|
let n = segment.len();
|
||||||
|
assert!(n > 40);
|
||||||
|
// timestamps that go back, then forward, and some that are missing
|
||||||
|
let times: Vec<_> = segment.iter().map(|p| p.time.unwrap()).collect();
|
||||||
|
segment.update_all(|i, pt| {
|
||||||
|
pt.time = match i {
|
||||||
|
10..=19 => Some(times[29 - i]),
|
||||||
|
20..=24 => None,
|
||||||
|
25..=29 => Some(times[0] - 1_000 * i as i64),
|
||||||
|
_ => pt.time,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
let stats = Statistics::compute(&segment);
|
||||||
|
let mut buffer = StatisticsBuffer::default();
|
||||||
|
buffer.update(&[(&segment, &stats)]);
|
||||||
|
|
||||||
|
for start in 0..n {
|
||||||
|
for end in start..n {
|
||||||
|
let slice = buffer.slice(start, end).unwrap();
|
||||||
|
for time in [slice.total_time, slice.moving_time].into_iter().flatten() {
|
||||||
|
assert!(time >= 0, "time of {start}..={end}");
|
||||||
|
}
|
||||||
|
for speed in [slice.total_speed(), slice.moving_speed()]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
assert!(
|
||||||
|
speed.is_finite() && speed >= 0.0,
|
||||||
|
"speed of {start}..={end}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_slice_of_a_range() {
|
fn test_slice_of_a_range() {
|
||||||
let (segment, s) = computed("data/with_time.gpx");
|
let (segment, s) = computed("data/with_time.gpx");
|
||||||
|
|||||||
Reference in new issue
Block a user