aboutsummaryrefslogtreecommitdiff
path: root/src/gpx.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpx.rs')
-rw-r--r--src/gpx.rs30
1 files changed, 27 insertions, 3 deletions
diff --git a/src/gpx.rs b/src/gpx.rs
index 9dd7725..fb9e00e 100644
--- a/src/gpx.rs
+++ b/src/gpx.rs
@@ -3,6 +3,9 @@
//! 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,
@@ -15,6 +18,7 @@ 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,
@@ -24,13 +28,17 @@ pub struct Coordinates {
impl Coordinates {
/// Calculates the [Web Mercator
/// projection](https://en.wikipedia.org/wiki/Web_Mercator_projection) of the coordinates.
- /// Returns the `(x, y)` 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) * 256.0 * (lambda + PI);
+ let x = 2u64.pow(zoom) as f64 / (2.0 * PI) * WIDTH * (lambda + PI);
let y =
- 2u64.pow(zoom) as f64 / (2.0 * PI) * 256.0 * (PI - (PI / 4.0 + phi / 2.0).tan().ln());
+ 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)
}
}
@@ -47,6 +55,7 @@ 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)?;
@@ -71,14 +80,26 @@ pub fn extract_from_str(input: &str) -> Result<Vec<Coordinates>> {
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 {
@@ -93,6 +114,9 @@ impl Compression {
}
}
+/// 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,