Files
2026-10-14 11:04:08 +00:00

109 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Garmin2OsmAnd v0.4 — Native Garmin IMG → OSM vector export
This adds a second C++ executable, `garmin2osm`, to the prior low-RAM `garmin2osmand` tile renderer. The original `garmin2osmand` **SQLiteDB raster exporter is unchanged in purpose**.
## Scope and results
This C++ export uses **no Dart, GeoJSON, `ogr2osm`, or Python runtime**. It shares the Garmin FAT/GMP, TRE/RGN, LBL/LBL6/NET and TYP decoders from the raster project. A disk-backed SQLite staging database deduplicates geographic vertices using 7-decimal-place coordinates, then emits OSM XML with all nodes before ways. The temporary database is deleted after a successful export unless `--keep-temp` is selected. Memory consumption does not scale with overall feature count, but output and staging *disk space* do.
The actual supplied 422 MiB Bulgaria IMG was scanned in full (165 map regions): 1,420,389 polylines, 924,553 area polygons, 416,165 points/POIs, without stopping on malformed geometry. A Rila–Malyovitsa regional OSM XML was parsed and checked for unique node IDs and valid way references.
**NOT VERIFIED:** entire-Bulgaria OSM file generation and compilation into OBF have not been run end-to-end. Road routability is **best effort**; Garmin routing metadata and NOD topology are not reconstructed. The original Garmin TYP bitmap patterns **cannot be represented in ordinary OSM geometry tags**, although `colour=*` and `garmin:type=*` are preserved for extended hiking-route features. Standard OsmAnd rendering might not show these colors; an OsmAnd rendering style or hiking route relation enrichment is a separate project.
The output is for personal/offline processing of maps you are legally allowed to reuse. **Do not upload converted Garmin objects to the public OSM database.** Their licence and OSM provenance are not established.
## Build on Ubuntu/Debian
```sh
sudo apt update
sudo apt install -y cmake g++ make libpng-dev libsqlite3-dev
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j "$(nproc)"
ctest --test-dir build --output-on-failure
```
## Inspect the IMG
```sh
./build/garmin2osm --input 'gmapsupp(2).img' --inspect
```
This reads all available subdivisions, prints counts for map features grouped by Garmin types, and shows embedded Garmin TYP color classes. No SQLite or XML output is created.
## Export all Bulgaria
```sh
./build/garmin2osm \
--input 'gmapsupp(2).img' \
--output Bulgaria-Garmin.osm
```
Full OSM export could need **several gigabytes of free disk space**, and building a full `.obf` can require significantly more for temporary MapCreator indexes. This is not a completed whole-Bulgaria benchmark. Run `--inspect` first and keep additional storage free.
## Export Rila/Malyovitsa area for testing
```sh
./build/garmin2osm \
--input 'gmapsupp(2).img' \
--bbox 23.28,42.11,23.47,42.27 \
--output Rila-Garmin.osm
```
`--bbox` skips non-overlapping Garmin subdivisions. Polylines that cross the bbox boundary are **not cut at the exact boundary**. Use a small export for validation before exporting a country.
The default **excludes contour line types 0x20–0x25**, as requested; add `--contours` if wanted. `--all-levels` includes less-detailed duplicated Garmin map levels and should normally be avoided. `--limit-maps N` is useful for diagnostic subsets. `--temp staging.sqlite` chooses the temporary database path, and `--keep-temp` retains it. Existing destinations are deliberately not overwritten.
### Vector contents
- Roads, track roads, footpaths and ordinary Garmin line features → OSM ways and `highway=*` where confidently matched.
- Named trails and colored Garmin extended RGN polylines → distinct path ways with `colour=*`, `trailblazed=yes`, and `garmin:route_overlay=yes`.
- Streams and rivers → `waterway=*`.
- Known Garmin polygon types → national parks, woods, lakes, scrub and others, as OSM closed ways.
- Named POIs → separate OSM nodes; specific Bulgarian map codes matched from real data: peaks, drinking water, mountain huts/shelters, signposts, information boards, viewpoints, churches, etc.
- Source codes are recorded as `garmin:type=0x...` for debugging and future tag refinements.
**Precision caveat:** `garmin:route_overlay=yes` ways are **marked-route overlays**, potentially coincident with physical `highway=path` or `highway=track` geometry. They are currently emitted with `highway=path` for basic visibility in OsmAnd. That may introduce duplicate or phantom routable edges. Do not depend on the generated OBF for safety-critical routing until you have independently validated its connectivity and access restrictions.
Unknown Garmin POI types are kept as named OSM nodes with `garmin:type=*`, but they may **not appear** in OsmAnd's POI index until added to its supported `poi_types.xml` or mapped to a verified standard type. Similarly, `colour=*` is not a guarantee of visible hiking stripe styles inside OBF.
## Compile to native OBF
Get **OsmAndMapCreator** from the official [OsmAnd instructions](https://osmand.net/docs/technical/map-creation/create-offline-maps-yourself/).
```sh
wget https://download.osmand.net/latest-night-build/OsmAndMapCreator-main.zip
unzip OsmAndMapCreator-main.zip -d OsmAndMapCreator
export JAVA_OPTS='-Xms256M -Xmx4096M'
./scripts/build_obf.sh "$PWD/OsmAndMapCreator" "$PWD/Rila-Garmin.osm"
```
You can also save storage and I/O bandwidth with `gzip -9 Rila-Garmin.osm` and pass `Rila-Garmin.osm.gz` to the same wrapper. The `generate-obf-no-address` command builds a map without the address index; paths, POIs and map geometry are still indexed based on OsmAnd's supported render/routing/POI tags. **This last compilation step was not run in the container** because the MapCreator binary could not be retrieved; only the native IMG → OSM exporter was compiled and tested.
For large datasets, geographically partition the source and compile separately. OsmAnd recommends `.obf` files below 2 GiB.
## Validate converted OSM XML
```sh
python3 - <<'PY'
import xml.etree.ElementTree as ET
from collections import Counter
counts=Counter()
for _,e in ET.iterparse('Rila-Garmin.osm',events=('end',)):
if e.tag in ('node','way','relation'):
counts[e.tag]+=1
e.clear()
print(counts)
PY
```
See `tests/test_vector.py` for a reference-integrity test of the synthetic Garmin fixture.
### Code and format references
- [QMapShack Garmin implementation](https://github.com/Maproom/qmapshack/blob/dev/src/qmapshack/map/CMapIMG.cpp) — GPLv3 background research
- [cGPSmapper polyline type list](https://www.manualsonline.com/manuals/mfg/garmin/gps_receiver_1_2.html?p=88)
- [Garmin area type documentation](https://wiki.openstreetmap.org/wiki/Editing_OSM_Map_On_Garmin/Area_Types)
- [OsmAnd's official offline map build documentation](https://osmand.net/docs/technical/map-creation/create-offline-maps-yourself/)
Project licence: GPL-3.0-or-later (LICENSE).