# `TerrainGenerator.Terrain`
[🔗](https://github.com/fabio-t/terrain-generator/blob/main/lib/terrain_generator/terrain.ex#L1)

A generated terrain.

All per-cell buffers are row-major binaries indexed as `y * width + x`:

  * `:heightmap` — 32-bit little-endian floats, elevation in `[0, 1]`
  * `:flow` — 32-bit little-endian floats, log-normalised flow
    accumulation in `[0, 1]` (a useful moisture proxy)
  * `:flow_accumulation` — 32-bit little-endian floats, raw upstream
    catchment in cells (each cell contributes 1); use this to size
    channels
  * `:rivers` — one byte per cell, `1` where a river runs
  * `:lakes` — one byte per cell, `1` where a lake holds standing water
  * `:ocean` — one byte per cell, `1` where the cell is sea, meaning at
    or below sea level *and* connected to the map border. A basin below
    sea level that is cut off from the sea is a lake, not ocean.

Binaries are cheap to pass around (they live outside the BEAM heap) and
can be consumed wholesale — e.g. uploaded to a GPU or sent over a socket
— or queried per cell with the accessors below.

# `t`

```elixir
@type t() :: %TerrainGenerator.Terrain{
  flow: binary(),
  flow_accumulation: binary(),
  height: pos_integer(),
  heightmap: binary(),
  lakes: binary(),
  ocean: binary(),
  rivers: binary(),
  sea_level: float(),
  width: pos_integer()
}
```

# `flow_accumulation_at`

```elixir
@spec flow_accumulation_at(t(), non_neg_integer(), non_neg_integer()) :: float()
```

Raw upstream catchment at `{x, y}`, in cells.

# `flow_at`

```elixir
@spec flow_at(t(), non_neg_integer(), non_neg_integer()) :: float()
```

Log-normalised flow accumulation at `{x, y}`, in `[0, 1]`.

# `height_at`

```elixir
@spec height_at(t(), non_neg_integer(), non_neg_integer()) :: float()
```

Elevation at `{x, y}`, in `[0, 1]`.

# `heightmap_list`

```elixir
@spec heightmap_list(t()) :: [float()]
```

The heightmap as a flat list of floats, row by row.

Convenient for exploration, but for large maps prefer working with the
binary directly.

# `lake?`

```elixir
@spec lake?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
```

Whether `{x, y}` lies in a lake.

# `ocean?`

```elixir
@spec ocean?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
```

Whether `{x, y}` is ocean: at or below sea level and connected to the map
border. Enclosed low ground is *not* ocean.

# `river?`

```elixir
@spec river?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
```

Whether a river runs through `{x, y}`.

# `water?`

```elixir
@spec water?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
```

Whether `{x, y}` is covered by water of any kind: ocean, lake or river.

This is a union of the three masks, not an elevation test — a closed
basin below sea level counts as lake, not ocean.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
