Skip to content

Repository files navigation

hgt

Go module to read elevation data from SRTM HGT files.

Supported data

  • 30m (1 arc second)
  • 90m (3 arc seconds)

Lookups take the nearest sample on the tile's grid, which spans the full degree: 3601 samples 1/3600° apart, or 1201 samples 1/1200° apart. A sample with no data returns ErrVoidData.

Usage

Single tile

t, err := hgt.OpenTile("data/N48E021.hgt")
if err != nil {
    log.Fatal(err)
}
defer t.Close()

e, err := t.At(hgt.Coord{Lon: 21.2613, Lat: 48.7162})
if err != nil {
    log.Println(err)
}
log.Printf("elevation=%d resolution=%s", e, t.Resolution)

Data directory

Store resolves whichever tile a coordinate falls in, opening it on demand and keeping recently used tiles in a bounded cache. It is safe for concurrent use.

s, err := hgt.OpenStore("data")
if err != nil {
    log.Fatal(err)
}
defer s.Close()

e, res, err := s.At(context.Background(), hgt.Coord{Lon: 21.2613, Lat: 48.7162})
if err != nil {
    log.Println(err)
}
log.Printf("elevation=%d resolution=%s", e, res)

Batched queries

AtBatch keeps one tile in hand across consecutive coordinates that fall in it — the shape of a GPS track. Results come back in input order, with per-point failures in Result.Err rather than aborting the batch. Tile has it too, without the context.

for i, r := range s.AtBatch(context.Background(), track) {
    if r.Err != nil {
        log.Printf("point %d: %s", i, r.Err)
        continue
    }
    log.Printf("point %d: elevation=%d resolution=%s", i, r.Elevation, r.Resolution)
}

AtBatchScattered takes the same arguments and returns results in the same input order, but resolves them tile by tile. It pays off only when a batch touches more tiles than the cache holds; on a track, or with a cache that fits the working set, it is slower than AtBatch.

At and AtBatch check the context before opening a tile (in a batch, at each tile change). They cannot interrupt a read already in flight. A cancelled batch fills the results it has not reached with the context error.

Store options

  • WithCache(c) — the tile cache. DefaultCache(n) is the built-in one, holding n tiles; a store with no WithCache gets 128.
  • WithMmapTiles() — memory-map each tile instead of reading it with ReadAt, avoiding a syscall per sample once the pages are resident. WithMmap does the same for a single OpenTile. Mapping is unix-only; on other platforms, and for any tile that cannot be mapped, it silently falls back to ReadAt.
  • WithPreloadTiles() — read each tile fully into the heap on open. Takes precedence over mmap, and makes the cache capacity a memory budget: a 1-arc-second tile is ~25 MB.
  • WithBounds(fn) — reject coordinates outside your dataset. Defaults to SRTM coverage, roughly 56°S to 60°N.
  • WithExtension(ext) — extension to resolve tile names with, instead of .hgt. The leading dot is optional; "" means no extension. A path separator in it is rejected.
s, err := hgt.OpenStore("data", hgt.WithExtension(".HGT"))

Missing tiles

Misses are remembered, so uncovered coordinates cost nothing after the first. Call Forget if tiles arrive while the store is live:

s.Forget()

A wrong-sized tile is never remembered — that is what a tile looks like mid-download — so it is retried until the write completes. Forget leaves cached tiles alone; an open tile keeps serving what it was opened on.

Custom cache

Implement hgt.Cache (Get, Add and Clear over hgt.TileKey and *hgt.Tile) for a residency policy of your own — an unbounded map, a budget in bytes, metrics, or nothing cached at all. A TileKey is the tile id (N48E021), extension excluded.

The cache owns the tiles it is given: it must call (*Tile).Close on every tile it drops, or that tile's descriptor leaks. Close is idempotent and never blocks on in-flight reads. All three methods must be safe for concurrent use, and a cache belongs to one Store.

s, err := hgt.OpenStore("data", hgt.WithCache(myCache))

The CLOCK cache behind DefaultCache lives in the hgt/cache subpackage, generic over key and value, if you would rather delegate to it than reimplement eviction.

Tests

The tests generate their own tiles, so no dataset is needed:

go test ./...

Fixtures go to a versioned temp directory (~80 MB) and are reused.

License

Licensed under MIT license.

About

Go module to read elevation data from SRTM HGT files.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages