aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2025-11-29 14:19:54 +0100
committerDaniel Schadt <kingdread@gmx.de>2025-11-29 14:19:54 +0100
commitd9ea39135564a86d26adeba097c2541a02140ade (patch)
tree4a74810f8fadfb326c22f34fbd60cded33a90169
parent918d06a7ffa92dce6dbf3a921263e56df1218bf0 (diff)
downloadhittekaart-d9ea39135564a86d26adeba097c2541a02140ade.tar.gz
hittekaart-d9ea39135564a86d26adeba097c2541a02140ade.tar.bz2
hittekaart-d9ea39135564a86d26adeba097c2541a02140ade.zip
add some more documentation
-rw-r--r--hittekaart/src/error.rs22
-rw-r--r--hittekaart/src/gpx.rs10
-rw-r--r--hittekaart/src/layer.rs5
-rw-r--r--hittekaart/src/lib.rs51
4 files changed, 75 insertions, 13 deletions
diff --git a/hittekaart/src/error.rs b/hittekaart/src/error.rs
index f5abd1b..16cd597 100644
--- a/hittekaart/src/error.rs
+++ b/hittekaart/src/error.rs
@@ -5,32 +5,52 @@ use thiserror::Error;
use super::renderer::RenderedTile;
+/// Main error type. All hittekaart errors are mapped to this enum.
#[derive(Error, Debug)]
pub enum Error {
+ /// Error for crossbeam operations.
+ ///
+ /// hittekaart uses multithreading internally to speed up tile generation. We use crossbeam to
+ /// pass messages between threads.
#[error("crossbeam error")]
- Crossbeam(#[from] crossbeam_channel::SendError::<RenderedTile>),
+ Crossbeam(#[from] crossbeam_channel::SendError<RenderedTile>),
+ /// Underlying image processing error.
#[error("image processing error")]
Image(#[from] image::ImageError),
+ /// The GPX file contains an invalid latitude value.
#[error("the latitude is invalid")]
InvalidLatitude(#[source] ParseFloatError),
+ /// The GPX file contains an invalid longitude value.
#[error("the longitude is invalid")]
InvalidLongitude(#[source] ParseFloatError),
+ /// The output directory is invalid.
#[error("the output directory is invalid")]
InvalidOutputDirectory,
+ /// Underlying I/O error.
+ ///
+ /// The first field contains a description of the action that was executed when the error
+ /// occurred.
#[error("error when {0} because of an underlying I/O error")]
Io(&'static str, #[source] std::io::Error),
+ /// The input point had no latitude value attached.
#[error("input has no latitude value")]
MissingLatitude,
+ /// The input point had no longitude value attached.
#[error("input has no longitude value")]
MissingLongitude,
+ /// The output folder already exists.
#[error("output file {0} already exists")]
OutputAlreadyExists(PathBuf),
+ /// Underlying SQLite error.
#[error("SQLite error")]
Sqlite(#[from] rusqlite::Error),
+ /// UTF-8 decoding error.
#[error("invalid utf8 input data")]
Utf8(#[from] FromUtf8Error),
+ /// XML parsing error.
#[error("XML parse error")]
Xml(#[from] roxmltree::Error),
}
+/// Type alias that defaults to [`enum@Error`] as error variant.
pub type Result<T, E = Error> = std::result::Result<T, E>;
diff --git a/hittekaart/src/gpx.rs b/hittekaart/src/gpx.rs
index 8bd076d..b645c21 100644
--- a/hittekaart/src/gpx.rs
+++ b/hittekaart/src/gpx.rs
@@ -1,8 +1,10 @@
//! 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)).
+//! Like the rest of hittekaart, this module is specialized to our use case. That's why this module
+//! internally uses [roxmltree](https://github.com/RazrFalcon/roxmltree) for fast XML parsing,
+//! instead of the [gpx](https://github.com/georust/gpx) crate that has more features.
+//!
+//! This module supports reading files that are `gzip` or `brotli` compressed.
//!
//! 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.
@@ -125,7 +127,7 @@ impl Compression {
/// 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
+ /// If the file does not end with any of the aforementioned extensions, `None` is returned
/// instead.
pub fn suggest_from_path<P: AsRef<Path>>(path: P) -> Option<Compression> {
let Some(ext) = path.as_ref().extension() else {
diff --git a/hittekaart/src/layer.rs b/hittekaart/src/layer.rs
index 03a168b..e8fea25 100644
--- a/hittekaart/src/layer.rs
+++ b/hittekaart/src/layer.rs
@@ -1,8 +1,7 @@
//! Lazy tiled image.
//!
-//! This supports OSM-style "tiled" images, but not all of the tiles have to be present. If a tile
-//! is not present, a default pixel is returned. The tile is allocated with the first call to a
-//! mutating operation.
+//! This represents an OSM tile layer with 256x256 map tiles, but "lazily" saved -- tiles are only
+//! allocated on the first write access.
use std::{
fs::File,
io::{BufWriter, Write},
diff --git a/hittekaart/src/lib.rs b/hittekaart/src/lib.rs
index 3a4c7a3..5d71d2c 100644
--- a/hittekaart/src/lib.rs
+++ b/hittekaart/src/lib.rs
@@ -1,10 +1,51 @@
-//! `hittekaart` is a program to generate heatmaps from GPX tracks.
+//! `hittekaart` is a crate to generate heatmaps from GPS tracks. It reads GPX files and produces
+//! OSM-compatible overlay tiles.
//!
-//! Note that this crate is not meant to be used as a library. Instead, use the command line
-//! program that is included in this crate.
+//! This crate is mainly written to power the CLI wrapper and the Python interface, and as such, is
+//! opinionated (and leaky) at points.
//!
-//! This library therefore contains an API that is tailored to the use case of the `hittekaart`
-//! binary.
+//! # Example
+//!
+//! ```
+//! use hittekaart::{gpx, renderer::{self, heatmap}, storage::{self, Storage}};
+//! const ZOOM: u32 = 10;
+//! let source =
+//! r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+//! <gpx xmlns="http://www.topografix.com/GPX/1/1" version="1.1">
+//! <trk>
+//! <trkseg>
+//! <trkpt lat="49.184246" lon="9.201409"></trkpt>
+//! </trkseg>
+//! </trk>
+//! </gpx>"#;
+//! let track = gpx::extract_from_str(source)?;
+//! let tracks = &[track];
+//! // Generating a heat-map is a two-step process: First, we collect the "heat zones", then we
+//! // render each zone to a PNG.
+//! let heat = renderer::prepare(
+//! &renderer::heatmap::Renderer,
+//! ZOOM,
+//! tracks,
+//! // A callback you can use to show progress
+//! || Ok(()),
+//! )?;
+//! // Before we run the second step, we set up the storage system. You can save the bytes in any
+//! // way you want, but there are convenience functions in this crate:
+//! let mut store = storage::Sqlite::connect(":memory:")?;
+//! store.prepare()?;
+//! store.prepare_zoom(ZOOM)?;
+//! // Now we're ready to do the actual colorizing
+//! renderer::colorize(
+//! &renderer::heatmap::Renderer,
+//! heat,
+//! // The callback receives the rendered tile, with the PNG data ready to grab.
+//! |tile| {
+//! store.store(ZOOM, tile.x, tile.y, &tile.data)
+//! },
+//! )?;
+//! store.finish()?;
+//! # Ok::<_, hittekaart::error::Error>(())
+//! ```
pub mod error;
pub mod gpx;
pub mod layer;