= hittekaart(1) :source-highlighter: rouge
== NAME
hittekaart - A GPX track heatmap generator.
== SYNOPSIS
hittekaart [--output=...] [--min-zoom=...] [--max-zoom=...] [--threads=...] [--format=...] FILES...
== INSTALLATION
You can build the binary ./target/release/hittekaart with cargo:
cargo build --release
== DESCRIPTION
hittekaart is a tool to generate heatmaps from GPX tracks. It reads a number
of GPX files and produces OSM-compatible overlay tiles. Note that hittekaart
itself does not display any maps, instead you can use the generated heatmap
tiles as overlay layers in other applications such as
https://leafletjs.com/[Leaflet] or
https://sourceforge.net/projects/viking/[Viking].
=== OUTPUT FORMAT
The generated tiles are saved according to the https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames[slippy map tilenames], so they can be served by any normal HTTP server.
By default, the directory tiles/ will be used as the root directory, so a
tile would be saved as tiles/{zoom}/{x}/{y}.png. You can change this by using
the --output/-o option.
=== SQLITE OUTPUT
In order to overcome storage overhead when saving many small files (see the tip
and table further below), hittekaart can instead output a SQLite database
with the heatmap tile data. Two formats are available for this:
OSMAND compatible output can be generated by the --format=osm-and option.
In this case, --output/-o can be used to control the output filename. The
OsmAnd format is relatively simple, its main data lies in a single tiles
table:
[source,sql]
CREATE TABLE tiles ( x INTEGER, y INTEGER, z INTEGER, image BLOB, time INTEGER, PRIMARY KEY (x, y, z) );
The time column is always NULL.
To use the map in the app, make sure to:
- Give it a
.sqlitedbextension, and - place it under
Android/data/net.osmand.plus/files/tiles/.
For a full reference of the format, see https://osmand.net/docs/technical/osmand-file-formats/osmand-sqlite/.
MBTILES files can be generated by the --format=mb-tiles option. Like OsmAnd
files, MBTiles are also SQLite databases. In this case, the main table has the
following scheme:
[source,sql]
CREATE TABLE tiles ( zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB, PRIMARY KEY (zoom_level, tile_column, tile_row) );
Note that the tile_row is inverted.
For a full reference of the format, see https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md.
=== INPUT FILES
hittekaart expects GPX track files with the .gpx extension. It will parse
them and read the track points. Optionally, you can feed it compressed GPX
files:
- Files ending with
.gzwill be consideredgzipcompressed and unpacked on reading. - Files ending with
.brwill be consideredbrotlicompressed and unpacked on reading.
=== MULTITHREADING
Heatmap generation involves some CPU intensive parts, namely the parsing of the
GPX files and the PNG compression. Especially the latter takes up a big part of
the heatmap generation. By default, hittekaart will parallelize those
processes, by default using as many threads as you have CPU cores.
If you want to limit the number of threads that will be used, for example
because you want to run the heatmap generation in the background, use the
--threads option. Setting a thread count of 0 will use the default behaviour
of using all cores, while setting it to any other number will use that many
threads. The setting --threads=1 effectively disables multithreading.
=== ZOOM LEVELS
By default, all zoom levels from 0 (a one-tile overview of the whole world) to
19 (the maximum that the openstreetmap.org tile server offers) will be
generated. However, you can control that setting with --min-zoom and
--max-zoom, for example if you don't want the heat maps to be as detailed.
Keep in mind that every zoom level has four times as many tiles as the previous zoom level, which quickly increases the number of tiles. This also means that the more detailed levels will take up considerably more space than previous levels. For example, a sample of 64 tracks leads to the following sizes:
[%header,cols="1,1,1,1"] |=== |Level |# Tiles |Size |Cum. Size
|0 |1 |8.4 KiB |8.4 KiB
|1 |1 |8.4 KiB |16.8 KiB
|2 |1 |8.4 KiB |25.2 KiB
|3 |1 |8.5 KiB |33.7 KiB
|4 |1 |8.7 KiB |42.4 KiB
|5 |2 |9.3 KiB |51.7 KiB
|6 |2 |9.9 KiB |61.6 KiB
|7 |2 |11 KiB |72.6 KiB
|8 |2 |13 KiB |85.6 KiB
|9 |3 |24 KiB |109.6 KiB
|10 |7 |40 KiB |149.6 KiB
|11 |23 |81 KiB |230.6 KiB
|12 |60 |173 KiB |403.6 KiB
|13 |160 |373 KiB |776.6 KiB
|14 |402 |813 KiB |1589.6 KiB
|15 |973 |1.8 MiB |3.4 MiB
|16 |2,294 |3.9 MiB |7.3 MiB
|17 |5,277 |8.1 MiB |15.4 MiB
|18 |11,638 |16 MiB |31.4 MiB
|19 |25,729 |34 MiB |65.4 MiB |===
You can see that starting at level 14, each single level takes as much space as all previous levels combined.
[TIP] .A Note on Small Files
The table shows the logical file sizes. Usually, the files are a bit bigger on disk, as the file size is not an exact multiple of the block size. For a standard block size of 4 KiB on an ext4 system for example, you would end up with a total of 195 MiB, 107 MiB just for zoom level 19. This is a massive increase in storage requirement, simply from the fact that the files do not fill up all allocated blocks.
If you intend to store a lot of heatmaps, it might be worth setting up a file system that is optimized for a large amount of small files, for example by setting a smaller block size. Many of the PNG images are smaller than 2 KiB (half a standard block); for those 50% of storage is wasted already.
If you don't need the tiles in separate files, you can use the SQLite output mode. For the same data as above, the SQLite database would be 73 MiB in size.
=== DIFFERENT OVERLAYS
By default, hittekaart generates a heatmap. However, it does also support
different modes:
tilehunter:: In this mode, a tile that is touched by at least one input track is marked as green. The goal is to get as big of a filled square as possible. The difference to marktile (see below) is that the markings operate on a fixed zoom level.
marktile:: In this mode, tiles that contain points are marked. The difference to tilehunter is that the marking doesn't scale and always operates on the map zoom level.
== OPTIONS
The following options are supported:
--min-zoom=ZOOMLEVEL::
Set the minimum zoom level to generate. Defaults to 0, which is a one-tile
overview of the world.
--max-zoom=ZOOMLEVEL::
Set the maximum zoom level to generate (inclusive). Defaults to 19, the
maximum zoom that the openstreetmap.org tile server offers.
-t THREADS, --threads=THREADS::
Sets the number of threads. Defaults to 0, which means that hittekaart
will automatically pick a default.
-o DIRECTORY, --output=DIRECTORY::
Generate the output tiles into the given directory. Defaults to tiles/
when generating single files, and tiles.sqlite when storing the tiles in
a SQLite database.
--format=FORMAT::
Sets the output format (folder, osm-and, mb-tiles). See the sections above
on OUTPUT FORMAT and SQLITE OUTPUT for more information.
-m MODE, --mode=MODE::
Sets the overlay generation mode (heatmap, marktile, tilehunter). See
section DIFFERENT OVERLAYS for more information.
--tilehunter-zoom=ZOOM::
Only effective in the tilehunter mode. Sets the zoom level at which the
tiles are marked.
== EXAMPLE
You can generate a heatmap and serve it locally with the following commands:
hittekaart ~/Documents/GPX/*.gpx cd tiles python -m http.server
With the tile server running, you can then open a HTML file like the following:
[source,html]
L.control.layers([osm], [heatmap]).addTo(map);
</script>
== HITTE AS A LIBRARY
If you want to use hittekaart as part of another application, you can use one
of the following methods:
=== RUST CRATE
The hittekaart binary is powered by the hittekaart crate, which you can
find at https://crates.io/crates/hittekaart, and its documentation at
https://docs.rs/hittekaart.
=== PYTHON LIBRARY
This program comes with a Python interface, which allows easy use from Python
scripts. The hittekaart_py subfolder in the repository is an installable
module.
The Python API is documented in the docstrings, and at https://docs.fietsboek.org/developer/module/hittekaart_py.html. An example program may look like:
[source,python]
from hittekaart_py import ( Track, HeatmapRenderer, Settings, Storage, generate )
settings = Settings(threads=3) tracks = [ Track.from_file(b"Documents/track.gpx", None), Track.from_coordinates([(45.0, 47.0)]), ] storage = Storage.Sqlite(b"/tmp/tiles.sqlite") generate(settings, tracks, HeatmapRenderer(), storage)
== BUGS
Feel free you report bugs on the issue tracker at https://gitlab.com/dunj3/hittekaart/-/issues or via email (see below).
== AUTHOR
Daniel Schadt - hittekaart at kingdread.de
== COPYRIGHT
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.