-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jeromos Kovacs
committed
Sep 25, 2024
1 parent
0bb1efa
commit f2fa00a
Showing
8 changed files
with
427 additions
and
275 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
fn main() { | ||
fit2gpx::convert_file("afternoon walk with dog.fit").unwrap(); | ||
println!(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use super::*; | ||
use rayon::prelude::*; | ||
use std::collections::HashMap; | ||
|
||
// TODO: docs | ||
pub fn needed_tile_coords(wps: &[Waypoint]) -> Vec<(i32, i32)> { | ||
// kinda Waypoint to (i32, i32) | ||
let trunc = |wp: &Waypoint| -> (i32, i32) { | ||
let (x, y) = wp.point().x_y(); | ||
(y.trunc() as i32, x.trunc() as i32) | ||
}; | ||
// tiles we need | ||
let mut needs = Vec::new(); | ||
for wp in wps.iter().filter(|wp| !is_00(wp)).map(trunc) { | ||
if !needs.contains(&wp) { | ||
needs.push(wp); | ||
} | ||
} | ||
needs | ||
} | ||
|
||
// TODO: docs | ||
pub fn read_needed_tiles( | ||
needs: &[(i32, i32)], | ||
elev_data_dir: Option<impl AsRef<Path>>, | ||
) -> Vec<srtm_reader::Tile> { | ||
if needs.is_empty() { | ||
return vec![]; | ||
} | ||
|
||
let elev_data_dir = if let Some(arg_data_dir) = &elev_data_dir { | ||
arg_data_dir.as_ref() | ||
} else if let Some(env_data_dir) = option_env!("ELEV_DATA_DIR") { | ||
Path::new(env_data_dir) | ||
} else if let Some(env_data_dir) = option_env!("elev_data_dir") { | ||
Path::new(env_data_dir) | ||
} else { | ||
panic!("no elevation data dir is passed as an arg nor set as an environment variable: ELEV_DATA_DIR"); | ||
}; | ||
needs | ||
.par_iter() | ||
.map(|c| srtm_reader::get_filename(*c)) | ||
.map(|t| elev_data_dir.join(t)) | ||
.map(|p| srtm_reader::Tile::from_file(p).inspect_err(|e| eprintln!("error: {e:#?}"))) | ||
.flatten() // ignore the ones with an error | ||
.collect::<Vec<_>>() | ||
} | ||
// TODO: don't panic | ||
// TODO: docs | ||
/// index the tiles with their coordinates | ||
pub fn get_all_elev_data<'a>( | ||
needs: &'a [(i32, i32)], | ||
tiles: &'a [srtm_reader::Tile], | ||
) -> HashMap<&'a (i32, i32), &'a srtm_reader::Tile> { | ||
assert_eq!(needs.len(), tiles.len()); | ||
needs | ||
.par_iter() | ||
.enumerate() | ||
.map(|(i, coord)| (coord, tiles.get(i).unwrap())) | ||
.collect::<HashMap<_, _>>() | ||
// eprintln!("loaded elevation data: {:?}", all_elev_data.keys()); | ||
} | ||
|
||
/// add elevation to all `wps` using `elev_data`, in parallel | ||
/// | ||
/// # Panics | ||
/// | ||
/// elevation data needed, but not loaded | ||
/// | ||
/// # Safety | ||
/// | ||
/// it's the caller's responsibility to have the necessary data loaded | ||
/// | ||
/// # Usage | ||
/// | ||
/// using the following order, it should be safe | ||
/// | ||
/// ``` | ||
/// use fit2gpx::elevation::*; | ||
/// | ||
/// let mut fit = fit2gpx::FitContext::from_file("evening walk.gpx").unwrap(); | ||
/// let elev_data_dir = Some("/home/me/Downloads/srtm_data"); | ||
/// let needed_tile_coords = needed_tile_coords(&fit.track_segment.points); | ||
/// let needed_tiles = needed_tiles(&needed_tile_coords, elev_data_dir); | ||
/// let all_elev_data = get_all_elev_data(&needed_tile_coords, &needed_tiles); | ||
/// | ||
/// add_elev_unchecked(&mut fit.track_segment.points, &all_elev_data); | ||
/// ``` | ||
pub fn add_elev_unchecked( | ||
wps: &mut [Waypoint], | ||
elev_data: &HashMap<&(i32, i32), &srtm_reader::Tile>, | ||
) { | ||
// coord is x,y but we need y,x | ||
let xy_yx = |wp: &Waypoint| -> srtm_reader::Coord { | ||
let (x, y) = wp.point().x_y(); | ||
(y, x).into() | ||
}; | ||
wps.into_par_iter() | ||
.filter(|wp| wp.elevation.is_none() && !is_00(wp)) | ||
.for_each(|wp| { | ||
let coord = xy_yx(wp); | ||
let elev_data = elev_data | ||
.get(&coord.trunc()) | ||
.expect("elevation data must be loaded"); | ||
wp.elevation = Some(elev_data.get(coord) as f64); | ||
}); | ||
} |
Oops, something went wrong.