diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2025-08-25 21:54:13 +0200 | 
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2025-08-25 21:54:13 +0200 | 
| commit | 888c23d0b9c50ff457be2cb300afe634f1d6fa59 (patch) | |
| tree | 9ef388ad197a89b48a02a6e5a88529d15e68036b /src/gpx.rs | |
| parent | 6adcd94a6747fe7ec6f1ad1073453636847a0bff (diff) | |
| parent | e888344ba561bc6a52f96f7a7bc2ad24be287a82 (diff) | |
| download | hittekaart-888c23d0b9c50ff457be2cb300afe634f1d6fa59.tar.gz hittekaart-888c23d0b9c50ff457be2cb300afe634f1d6fa59.tar.bz2 hittekaart-888c23d0b9c50ff457be2cb300afe634f1d6fa59.zip  | |
Merge branch 'py'
Diffstat (limited to 'src/gpx.rs')
| -rw-r--r-- | src/gpx.rs | 138 | 
1 files changed, 0 insertions, 138 deletions
diff --git a/src/gpx.rs b/src/gpx.rs deleted file mode 100644 index fb9e00e..0000000 --- a/src/gpx.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! GPX data extraction functions. -//! -//! We *could* use the [gpx](https://github.com/georust/gpx) crate, but we don't care about much -//! other than the coordinates of the tracks. By implementing the little functionality ourselves, -//! we can use a fast XML parser ([roxmltree](https://github.com/RazrFalcon/roxmltree)). -//! -//! Note that we throw away all information that we don't care about. Since we need only the -//! coordinates of a track, we simply use a `Vec<Coordinates>` to represent a track. -use std::{ -    f64::consts::PI, -    ffi::OsStr, -    fs::{self, File}, -    io::{BufReader, Read}, -    path::Path, -}; - -use color_eyre::eyre::{eyre, Result}; -use flate2::bufread::GzDecoder; -use roxmltree::{Document, Node, NodeType}; - -/// World coordinates. -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Coordinates { -    longitude: f64, -    latitude: f64, -} - -impl Coordinates { -    /// Calculates the [Web Mercator -    /// projection](https://en.wikipedia.org/wiki/Web_Mercator_projection) of the coordinates. -    /// -    /// Returns the `(x, y)` projection, where both are in the range `[0, 256 * 2^zoom)`. -    pub fn web_mercator(self, zoom: u32) -> (u64, u64) { -        const WIDTH: f64 = super::layer::TILE_WIDTH as f64; -        const HEIGHT: f64 = super::layer::TILE_HEIGHT as f64; - -        let lambda = self.longitude.to_radians(); -        let phi = self.latitude.to_radians(); -        let x = 2u64.pow(zoom) as f64 / (2.0 * PI) * WIDTH * (lambda + PI); -        let y = -            2u64.pow(zoom) as f64 / (2.0 * PI) * HEIGHT * (PI - (PI / 4.0 + phi / 2.0).tan().ln()); -        (x.floor() as u64, y.floor() as u64) -    } -} - -fn is_track_node(node: &Node) -> bool { -    node.node_type() == NodeType::Element && node.tag_name().name() == "trk" -} - -fn is_track_segment(node: &Node) -> bool { -    node.node_type() == NodeType::Element && node.tag_name().name() == "trkseg" -} - -fn is_track_point(node: &Node) -> bool { -    node.node_type() == NodeType::Element && node.tag_name().name() == "trkpt" -} - -/// Extracts a track from the given string. -pub fn extract_from_str(input: &str) -> Result<Vec<Coordinates>> { -    let mut result = Vec::new(); -    let document = Document::parse(input)?; -    for node in document.root_element().children().filter(is_track_node) { -        for segment in node.children().filter(is_track_segment) { -            for point in segment.children().filter(is_track_point) { -                let latitude = point -                    .attribute("lat") -                    .and_then(|l| l.parse::<f64>().ok()) -                    .ok_or_else(|| eyre!("Invalid latitude"))?; -                let longitude = point -                    .attribute("lon") -                    .and_then(|l| l.parse::<f64>().ok()) -                    .ok_or_else(|| eyre!("Invalid longitude"))?; -                result.push(Coordinates { -                    latitude, -                    longitude, -                }); -            } -        } -    } -    Ok(result) -} - -/// Compression format of the data. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Compression { -    /// Indicates that no compression is applied, and the file is plain GPX. -    None, -    /// Indicates that the file is gzip compressed. -    Gzip, -    /// Indicates that the file is brotli compressed. -    Brotli, -} - -impl Compression { -    /// Suggests a [`Compression`] from the given path name. -    /// -    /// This will suggest [`Compression::Brotli`] for files ending in `.br`, [`Compression::Gzip`] -    /// for files ending with `.gz` or `.gzip`, and [`Compression::None`] for files ending with -    /// `.gpx`. -    /// -    /// If the file does not end with any of the aforementioned extensions, an error is returned -    /// instead. -    pub fn suggest_from_path<P: AsRef<Path>>(path: P) -> Option<Compression> { -        let Some(ext) = path.as_ref().extension() else { return None }; -        if OsStr::new("br") == ext { -            Some(Compression::Brotli) -        } else if [OsStr::new("gz"), OsStr::new("gzip")].contains(&ext) { -            Some(Compression::Gzip) -        } else if OsStr::new("gpx") == ext { -            Some(Compression::None) -        } else { -            None -        } -    } -} - -/// Extracts the relevant GPX data from the given file. -/// -/// Note that the content must be valid UTF-8, as that is what our parser expects. -pub fn extract_from_file<P: AsRef<Path>>( -    path: P, -    compression: Compression, -) -> Result<Vec<Coordinates>> { -    let content = match compression { -        Compression::None => fs::read_to_string(path)?, -        Compression::Gzip => { -            let mut result = String::new(); -            GzDecoder::new(BufReader::new(File::open(path)?)).read_to_string(&mut result)?; -            result -        } -        Compression::Brotli => { -            let mut result = Vec::new(); -            brotli::BrotliDecompress(&mut BufReader::new(File::open(path)?), &mut result)?; -            String::from_utf8(result)? -        } -    }; -    extract_from_str(&content) -}  | 
