English | Français
gpxsolar casts a ray toward the sun from every point of a GPX track and tests it against the terrain and the vegetation (0.5 m HD LiDAR / IGN), for a given date and time. It tells you, meter by meter, sun or shade.
Will I be in sun or shade on my hike? gpxsolar ray-traces the sun against terrain and vegetation (0.5 m LiDAR) along a GPX track, for a given date and time — point by point, sun or shade.
Outputs: KMZ (Google Earth), MBTiles overlay + KML track (Locus Map / OsmAnd) and CSV.
A self-contained Python tool that takes a GPX track, a start date and time, then computes for each point of the route whether it is in sun or shade, accounting for the terrain (digital elevation model) and the vegetation (ESA WorldCover). It produces a colorized KML/KMZ to open in Google Earth and a CSV summary.
⚠️ Status: personal project, publicly released. Developed and tested on Windows 10/11. Linux and macOS are supported by the build architecture but tested partially — known cases + cross-OS troubleshooting in the Troubleshooting section of BUILD.md. Feedback welcome via GitHub issues.
From a GPX file + date/time:
- Sun-exposure profile along the track: each point is classified
sun / shade by simulating the sun's position (azimuth + altitude via
pysolar) and casting a ray against the terrain and the canopy. - Relief shadows from a DEM, with several elevation sources to choose from:
- SRTM1 / Copernicus DEM — global, low/medium resolution
- IGN BD ALTI 25 m — France, medium resolution
- IGN RGE ALTI 5 m — France, high resolution
- IGN LiDAR HD 0.5 m — France, very high resolution (DTM, DSM, CHM)
- Vegetation shadows via ESA WorldCover (estimated canopy height), which can be disabled.
- Slope mode (
--analysis-type pente, an alternative to sun/shade): colors the track by gradient computed from the DEM, never from the GPX elevation (which GPS makes unreliable). For France sources it queries the IGN RGE ALTI 1 m elevation point API, so it downloads no tiles. The analysis resolution sets the slope smoothing window, and travel-direction arrows are optional (--show-slope-arrows). - Outputs: colorized KMZ (Google Earth), MBTiles overlay + KML track for smartphone GPS apps (Locus Map, OsmAnd…), and an aggregated CSV. Optional timestamped waypoints along the route. Details of the files and smartphone overlay: see Output files.
Two ways to use gpxsolar:
| A. Python script | B. Standalone executable | |
|---|---|---|
| Requirements | Python 3.12 | None |
| First install | ~5 min (deps bootstrap) | None |
| Updates | git pull + relaunch |
Patch the bundle in one command: python update_app.py (or --release for all 3 OSes — see update_app.py) |
| Distributable | No — each user installs Python | Yes — .exe / .app / Linux binary + gpxsolar_bundle.zip side by side |
| Best for | dev / Linux / contributing | end user / distributing |
On first launch, the script creates ~/.gpxsolar/venv and installs its
dependencies there (numpy, pyproj, rasterio, shapely, pysolar, pywebview + PyQt6/QtWebEngine,
simplekml, timezonefinder, gpxpy, pandas…). ~300-400 MB, once.
git clone https://github.com/nico579/gpxsolar
cd gpxsolar
python gpxsolar.pybrew install python@3.12
git clone https://github.com/nico579/gpxsolar
cd gpxsolar
python3.12 gpxsolar.pysudo apt install python3.12 python3.12-venv git
git clone https://github.com/nico579/gpxsolar
cd gpxsolar
python3.12 gpxsolar.pyBootstrap modes: --bootstrap=auto (default, isolated venv), --bootstrap=pip
(install into the current Python), --bootstrap=none (check only),
--help-bootstrap (help).
No Python for the end user to install. The deliverable carries its own runtime (embedded Python + dependencies).
Option a — Download from Releases:
| OS | Archive | Extract with |
|---|---|---|
| Windows 10/11 (x86_64) | gpxsolar-windows-x86_64.zip |
Expand-Archive or double-click |
| Linux Ubuntu 24.04+ (x86_64) | gpxsolar-linux-x86_64.tar.gz |
tar xzf |
| macOS 12+ (Apple Silicon) | gpxsolar-macos-arm64.zip |
unzip then xattr -dr com.apple.quarantine GPXSOLAR.app |
The archive contains the binary/launcher and its gpxsolar_bundle.zip side by side.
Option b — Build it yourself. A machine setup script (do once) then a
build script (re-run each time gpxsolar.py is updated).
git clone https://github.com/nico579/gpxsolar
cd gpxsolar
.\setup_build_windows.ps1 # 1. Setup: Python 3.12, deps, PyInstaller
.\gpxsolar_win_build.ps1 # 2. Build -> dist\gpxsolar.exe + dist\gpxsolar_bundle.zipgit clone https://github.com/nico579/gpxsolar
cd gpxsolar
bash setup_build_mac.sh # 1. Setup
bash gpxsolar_mac_build.sh # 2. Build -> dist/GPXSOLAR.app + dist/gpxsolar-macos-arm64.zipLinux reuses the gpxsolar_win.spec spec (PyInstaller produces an ELF on Linux —
the _win name is misleading).
git clone https://github.com/nico579/gpxsolar
cd gpxsolar
bash setup_build_linux.sh # 1. Setup
bash gpxsolar_linux_build.sh # 2. Build -> dist/gpxsolar + dist/gpxsolar_bundle.zipFull build documentation (bundle architecture, updating without rebuild, troubleshooting): BUILD.md.
| OS | Command |
|---|---|
| Windows | Double-click gpxsolar.exe (or a terminal to see the log) |
| Linux | chmod +x gpxsolar && ./gpxsolar in the extracted folder |
| macOS | Double-click GPXSOLAR.app. First launch blocked by Gatekeeper: xattr -dr com.apple.quarantine GPXSOLAR.app then double-click |
The first launch extracts the bundle (~20-30 s, once — it contains Qt) into:
- Windows:
%LOCALAPPDATA%\gpxsolar\ - macOS:
~/Library/Application Support/gpxsolar/ - Linux:
~/.local/share/gpxsolar/
Clean uninstall: gpxsolar(.exe) --desinstaller (removes the extracted bundle
- the venv).
Two modes, selected automatically based on the arguments (same logic as the twin project lidar2map):
- No argument → graphical interface (pywebview). The common mode.
- With arguments → command-line computation (headless, no window). Handy for scripting, running on a server, or reproducing an exact render.
| Platform | Launch |
|---|---|
| Windows | double-click gpxsolar.exe (or a terminal to see the log) |
| Linux | ./gpxsolar in the extracted folder |
| macOS | double-click GPXSOLAR.app |
| Script (dev) | python gpxsolar.py |
Then in the window:
- Choose a GPX file.
- Select the date and start time.
- Choose an elevation source: SRTM/Copernicus (global), IGN ALTI (France), IGN LiDAR HD (France, DTM/DSM/CHM).
- Choose the analysis type (sun/shade, or slope coloring) and set the options (shadow type, vegetation, analysis resolution).
- Run the computation → KML/KMZ + CSV.
As soon as you pass an argument, gpxsolar computes without opening a window and
writes the outputs into GPX_Ombres/ (KMZ / MBTiles / KML depending on the options —
see Output files), plus the CSV. The minimum required is
--gpx + --date (DD/MM/YYYY) + --time (HH:MM). Everything below applies to the
binary as well as the script — just replace gpxsolar.exe with
./gpxsolar (Linux) or python gpxsolar.py (dev).
The three commands below reproduce exactly the three Google Earth renders in the Screenshots section:
# 1) Colored sun / shade track (basic render)
gpxsolar.exe --gpx hike.gpx --date 21/06/2024 --time 09:00 --dem-source ign_lidar_hd
# 2) + base map (raster shadow map in KMZ)
gpxsolar.exe --gpx hike.gpx --date 21/06/2024 --time 09:00 --dem-source ign_lidar_hd `
--generate-shadow-map
# 3) + simulated sun rays
gpxsolar.exe --gpx hike.gpx --date 21/06/2024 --time 09:00 --dem-source ign_lidar_hd `
--generate-shadow-map --visualize-sun-rays --sun-ray-interval 20The backtick
`is the PowerShell line continuation. On Linux/macOS, use\or put everything on a single line.
All outputs land in GPX_Ombres/. The <base> prefix encodes the GPX, the date,
the time, the elevation source, the shadow type and the direction.
Without --generate-shadow-map (track only):
| File | Content | For |
|---|---|---|
<base>.kml |
colored sun/shade track (vector) | Google Earth, Locus, OsmAnd, QGIS |
With --generate-shadow-map (track + shadow map) — three files, one per use:
| File | Content | For |
|---|---|---|
<base>.kmz |
all-in-one: colored track + shadow map | Google Earth (desktop) |
<base>.mbtiles |
shadow map only, raster overlay (PNG tiles, Web Mercator) | Locus Map / OsmAnd / OruxMaps / QGIS |
<base>_trace.kml |
colored track only (vector) | Locus Map / OsmAnd (as a track) |
Plus the CSV summary (analyse_solaire.csv by default), one line per run.
Google Earth reads the KMZ (shadow image + track merged) without trouble. But smartphone apps handle the KML GroundOverlay poorly: so we give them the shadow map as MBTiles (the raster overlay standard they can all display) and the track as a separate KML.
The instinct "I can only enable one map overlay" is correct — but a GPS app has three independent layers:
- the base map (topo, satellite…);
- one map overlay on top → that's the shadow
.mbtiles; - as many tracks/routes as you want → that's the
_trace.kml.
A track is not a "map": it doesn't count toward the single-overlay limit. So you load the shadow and the track as two layers of different kinds, and they display together.
Locus Map:
- Shadow: copy
<base>.mbtilesintoLocus/mapItems/(orLocus/maps/), then enable it as an overlay (map manager → overlay button). Leave the layer opacity at 100 % (see the note below). - Track: import
<base>_trace.kml→ it appears as a track, crisp and clickable, on top of the overlay.
OsmAnd:
- Shadow: Configure map → Overlay map layer → choose the
.mbtiles. Leave the layer transparency at maximum / at 0 %. - Track: My Places / Tracks → import the
.kml(or.gpx).
Leave the layer opacity at 100 % in Locus/OsmAnd. The semi-transparency is already baked into the tiles (the shadow lets the topo base show through) — nothing to adjust. Lowering the layer opacity only emphasizes a Locus artifact.
Faint tile seams in Locus: Locus draws the tiles of a semi-transparent overlay with a slight overlap, which leaves thin lines at the tile edges. This is a Locus rendering limitation (format-independent: MBTiles, RMAP or SQLitedb all show the same), not a data defect — the tiles are pixel-perfectly contiguous. QGIS and Google Earth render seamlessly. For GIS, prefer the GeoTIFF (EPSG:2154) or the MBTiles opened in QGIS anyway.
Main options (full list: gpxsolar.exe --help):
--gpx PATH # GPX file (triggers command-line mode)
--date DD/MM/YYYY --time HH:MM # start date and time
--dem-source {srtm1,copernicus,ign_bdalti_25m,ign_rgealti_5m,ign_lidar_hd}
--analysis-type {ombre_soleil,pente} # sun/shade (default) or slope coloring
--shadow-mode {relief,vegetation,both} # shadow type (default: both)
--direction {CW,CCW,both} # simulated travel direction (default: both)
--generate-shadow-map # raster shadow map (base map) in KMZ
--visualize-sun-rays # draw the sun rays
--visualize-tiles # draw the DEM tiles used
--show-slope-arrows # travel-direction arrows (slope mode)
--sun-ray-interval 20 # spacing of the sun rays
--analysis-resolution 5.0 # shadow sampling step, or slope smoothing window (m)
--max-shadow-distance 1000 # max shadow-detection range (m)
--margin-meters 500 # bbox margin around the track, shadow map (m)
--passage-interval-min 0 # timestamped waypoints (0=none)
--no-vegetation-shadow # ignore the vegetation shadow
--no-download-vegetation # do not download WorldCover
--output analyse_solaire.csv # output CSV name
--open # open the result at the end (Windows)
The same hike at 9:00, 13:00 and 18:00 (3D satellite view, Google Earth): the cast shadow sweeps across the hillside as the sun moves.
pywebview form: GPX choice, start date and time, elevation source (SRTM / Copernicus / IGN ALTI / IGN LiDAR HD), analysis type (sun/shade or slope), shadow type and options. In slope mode the shadow-only fields are hidden.
| Sun / shade analysis | Slope analysis (from DEM) |
|---|---|
The GPX track colorized sun / shade along the route, with the terrain, the base map and the simulated sun rays.
| Colored sun/shade track | + base map | + sun rays |
|---|---|---|
And in slope mode (--analysis-type pente), the track is colored by gradient
computed from the DEM (green = flat, through orange, to dark red = steep):
- User README: this file
- Build & deployment: BUILD.md — bundle architecture, per-OS scripts, updating without rebuild, troubleshooting (including Linux- and macOS-specific cases)
- Built-in help:
python gpxsolar.py --help
Code distributed under the GNU General Public License v3.0 — see LICENSE. You are free to use, modify and redistribute under the terms of the GPL v3.
Designed and architected by Nicolas Martin (@nico579). Code developed with the assistance of Claude (Anthropic) as a development tool.
Data and tools:
- IGN — BD ALTI, RGE ALTI, LiDAR HD (Etalab 2.0 license)
- NASA / USGS — SRTM; Copernicus — DEM GLO-30
- ESA WorldCover — land cover / vegetation
- Libraries: pysolar, pyproj, rasterio, shapely, numpy, pandas, gpxpy, simplekml, timezonefinder, pywebview, Pillow, numba.

