mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-17 08:42:28 +00:00
progress
This commit is contained in:
1 parent
41b9116c6a
commit
97d597e139
181 files changed
+1970
-2643
No files matched your search
@@ -0,0 +1,141 @@
|
||||
#[macro_export]
|
||||
macro_rules! for_each_window {
|
||||
(
|
||||
$trkseg:expr,
|
||||
$left:expr,
|
||||
$right:expr,
|
||||
$window:expr,
|
||||
|$a:ident, $b:ident| $distance:expr,
|
||||
|$i:ident, $l:ident, $r:ident| $body:block,
|
||||
) => {{
|
||||
let mut window_start = $left.unwrap_or_default();
|
||||
let mut window_center = $left;
|
||||
let mut window_end = $left.unwrap_or_default();
|
||||
while let Some(idx) = window_center {
|
||||
// advance left if needed
|
||||
while window_start != idx && {
|
||||
let $a = window_start;
|
||||
let $b = idx;
|
||||
$distance
|
||||
} > $window {
|
||||
if let Some(next) = $trkseg.next_index(Some(window_start)) {
|
||||
if next == idx {
|
||||
break;
|
||||
}
|
||||
window_start = next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// advance right if needed
|
||||
window_end = window_end.max(idx);
|
||||
while let Some(next) = $trkseg.next_index(Some(window_end)) {
|
||||
if window_end != idx && {
|
||||
let $a = idx;
|
||||
let $b = next;
|
||||
$distance
|
||||
} > $window {
|
||||
break;
|
||||
}
|
||||
window_end = next;
|
||||
}
|
||||
// apply body
|
||||
let $i = idx;
|
||||
let $l = window_start;
|
||||
let $r = window_end;
|
||||
$body
|
||||
// go next
|
||||
if window_center == $right {
|
||||
break;
|
||||
}
|
||||
window_center = $trkseg.next_index(window_center);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{TrackSegment, Trackpoint, TrackpointChunk};
|
||||
|
||||
fn segment(eles: &[f64]) -> TrackSegment {
|
||||
let mut trkseg = TrackSegment::default();
|
||||
// several small chunks, to also exercise the chunk boundaries
|
||||
for part in eles.chunks(3) {
|
||||
let mut chunk = TrackpointChunk::default();
|
||||
for ele in part {
|
||||
chunk.trkpt.push(Trackpoint {
|
||||
ele: *ele,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
trkseg.push(chunk);
|
||||
}
|
||||
trkseg
|
||||
}
|
||||
|
||||
/// Returns (center, left, right) flat indices for each visited center.
|
||||
fn windows(len: usize, window: f64) -> Vec<(usize, usize, usize)> {
|
||||
let trkseg = segment(&vec![0.0; len]);
|
||||
let mut visited = vec![];
|
||||
for_each_window!(
|
||||
trkseg,
|
||||
trkseg.first_index(),
|
||||
trkseg.last_index(),
|
||||
window,
|
||||
|a, b| (b.flat - a.flat) as f64,
|
||||
|i, l, r| {
|
||||
visited.push((i.flat, l.flat, r.flat));
|
||||
},
|
||||
);
|
||||
visited
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_bounds() {
|
||||
let visited = windows(10, 2.0);
|
||||
assert_eq!(visited.len(), 10);
|
||||
for (i, l, r) in visited {
|
||||
assert_eq!(l, i.saturating_sub(2), "left of {i}");
|
||||
assert_eq!(r, (i + 2).min(9), "right of {i}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_always_includes_neighbours() {
|
||||
for (i, l, r) in windows(6, 0.0) {
|
||||
assert_eq!((l, r), (i.saturating_sub(1), (i + 1).min(5)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_larger_than_segment() {
|
||||
for (_, l, r) in windows(5, 100.0) {
|
||||
assert_eq!((l, r), (0, 4));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_sub_range() {
|
||||
let trkseg = segment(&[0.0; 10]);
|
||||
let mut centers = vec![];
|
||||
let mut first = trkseg.first_index();
|
||||
for _ in 0..3 {
|
||||
first = trkseg.next_index(first);
|
||||
}
|
||||
let mut last = first;
|
||||
for _ in 0..2 {
|
||||
last = trkseg.next_index(last);
|
||||
}
|
||||
for_each_window!(
|
||||
trkseg,
|
||||
first,
|
||||
last,
|
||||
1.0,
|
||||
|a, b| (b.flat - a.flat) as f64,
|
||||
|i, _l, _r| {
|
||||
centers.push(i.flat);
|
||||
},
|
||||
);
|
||||
assert_eq!(centers, vec![3, 4, 5]);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user