BGrid Protocol

Technical specification for implementing the BGrid geospatial indexing system.

Technical Specification

This document defines the BGrid protocol for geospatial indexing. It is intended for developers who wish to implement BGrid in any programming language.

1. Overview

BGrid is a hierarchical spatial index that maps latitude/longitude coordinates to a sequence of integers in the range 1–2048 (11 bits of information each). These integers are typically represented by words from a BIP39 wordlist.

  • Input: WGS84 Coordinates (Latitude, Longitude)
  • Output: Array of indices [i1,i2,...,in][i_1, i_2, ..., i_n] where 1≤ik≤20481 \le i_k \le 2048.

2. Coordinate System

  • Latitude range: [−90,90][-90, 90] representing South to North.
  • Longitude range: [−180,180][-180, 180] representing West to East.
  • Datum: WGS84 is assumed.
  • Projection: the grid is defined directly on latitude/longitude degrees (equirectangular). Cells have equal angular size, not equal area.

3. Grid Structure

The grid is defined recursively. At each level, the parent cell is subdivided into a fixed number of child cells.

Subdivision Strategy

To keep cell proportions bounded, the grid orientation alternates between levels:

LevelColumns (divlondiv_{lon})Rows (divlatdiv_{lat})Total CellsGrid shapeResulting cell (in degrees)
Odd (1, 3, …)64322048Wide (2:1)Square (1:1)
Even (2, 4, …)32642048Tall (1:2)Twice as wide as tall (2:1)

The world spans 360° of longitude and 180° of latitude, so the level-1 grid of 64×32 produces square cells of 5.625° × 5.625°. Splitting a square cell into 32 columns and 64 rows yields cells twice as wide as tall (level 2); splitting those into 64 columns and 32 rows returns to square (level 3), and so on. Without alternation the ratio would double at every level.

Physical proportions also depend on latitude: a degree of longitude shrinks with cos⁡ϕ\cos\phi, so cells become narrower toward the poles. At about 60° latitude, even-level cells are roughly square on the ground and odd-level cells are about twice as tall as they are wide.

4. Encoding Algorithm

To convert a coordinate (ϕ,λ)(\phi, \lambda) (Lat, Lon) to a BGrid path of depth LL:

Initialization

Normalize the coordinates to the unit interval [0,1][0, 1]:

x0=λ+180360x_0 = \frac{\lambda + 180}{360} y0=90−ϕ180y_0 = \frac{90 - \phi}{180}

Iteration

For each level kk from 1 to LL:

  1. Determine Divisors:

    • If kk is odd: Wk=64,Hk=32W_k = 64, H_k = 32
    • If kk is even: Wk=32,Hk=64W_k = 32, H_k = 64
  2. Calculate Cell Indices:

    colk=⌊xk−1×Wk⌋col_k = \lfloor x_{k-1} \times W_k \rfloor rowk=⌊yk−1×Hk⌋row_k = \lfloor y_{k-1} \times H_k \rfloor
  3. Clamp Indices (Handle edge cases like +180 lon):

    colk=min⁡(max⁡(colk,0),Wk−1)col_k = \min(\max(col_k, 0), W_k - 1) rowk=min⁡(max⁡(rowk,0),Hk−1)row_k = \min(\max(row_k, 0), H_k - 1)
  4. Compute 1-based Index:

    Indexk=(rowk×Wk)+colk+1Index_k = (row_k \times W_k) + col_k + 1
  5. Update Normalized Coordinates (Zoom in for next iteration):

    xk=(xk−1×Wk)−colkx_k = (x_{k-1} \times W_k) - col_k yk=(yk−1×Hk)−rowky_k = (y_{k-1} \times H_k) - row_k
  6. Append IndexkIndex_k to result.

Implementations should follow this iterative procedure using IEEE 754 double precision, so that points lying exactly on a cell boundary encode identically across implementations.

Boundary Rules

These rules follow from the use of ⌊⋅⌋\lfloor \cdot \rfloor and clamping:

  • A point on a vertical boundary belongs to the cell to its east; a point on a horizontal boundary belongs to the cell to its south. In other words, each cell includes its west and north edges.
  • Longitude +180+180 is clamped into the easternmost column, so −180-180 and +180+180 (the same meridian) encode to different cells.
  • Latitude −90-90 is clamped into the southernmost row.

Hierarchy

Truncating an address yields the cell that contains it: the first nn indices of a path identify the level-nn ancestor cell. This is what allows sharing a location at reduced precision.

5. Decoding Algorithm

To convert a BGrid path [i1,i2,...,iL][i_1, i_2, ..., i_L] back to a coordinate and bounds:

Initialization

Start with global bounds:

  • MinLon0=−180,MaxLon0=180MinLon_0 = -180, MaxLon_0 = 180
  • MinLat0=−90,MaxLat0=90MinLat_0 = -90, MaxLat_0 = 90

Iteration

For each level kk corresponding to index iki_k:

  1. Adjust to 0-based index:

    idx=ik−1idx = i_k - 1
  2. Determine Divisors:

    • If kk is odd: Wk=64,Hk=32W_k = 64, H_k = 32
    • If kk is even: Wk=32,Hk=64W_k = 32, H_k = 64
  3. Decode Row/Col:

    col=idx(modWk)col = idx \pmod{W_k} row=⌊idx/Wk⌋row = \lfloor idx / W_k \rfloor
  4. Calculate Cell Dimensions:

    Δlon=MaxLonk−1−MinLonk−1Wk\Delta_{lon} = \frac{MaxLon_{k-1} - MinLon_{k-1}}{W_k} Δlat=MaxLatk−1−MinLatk−1Hk\Delta_{lat} = \frac{MaxLat_{k-1} - MinLat_{k-1}}{H_k}
  5. Update Bounds:

    MinLonk=MinLonk−1+(col×Δlon)MinLon_k = MinLon_{k-1} + (col \times \Delta_{lon}) MaxLonk=MinLonk+ΔlonMaxLon_k = MinLon_k + \Delta_{lon}

    Note: BGrid iterates Latitude from North (90) to South (-90) (top-down in grid terms).

    MaxLatk=MaxLatk−1−(row×Δlat)MaxLat_k = MaxLat_{k-1} - (row \times \Delta_{lat}) MinLatk=MaxLatk−ΔlatMinLat_k = MaxLat_k - \Delta_{lat}

Final Result

The resulting bounds [[MinLatL,MinLonL],[MaxLatL,MaxLonL]][[MinLat_L, MinLon_L], [MaxLat_L, MaxLon_L]] define the area covered by the BGrid address. The point coordinate is typically the center of these bounds.

6. String Representation

The numeric indices map to the BIP39 wordlists, each of which contains exactly 2048 words. Index ii corresponds to the ii-th word of the list (1-based):

  • Index 1 →\rightarrow abandon (English)
  • Index 2048 →\rightarrow zoo (English)

Because every wordlist has the same 2048 positions, the same address can be rendered in any supported language. For example, ability,smoke,board (English) and abdomen,ron,avena (Spanish) both identify the cell [2, 1639, 198].

Supported Wordlists

CodeLanguageNotes
enEnglish
esSpanishOfficial BIP39 list with accents removed
frFrench
itItalian
ptPortuguese
csCzechAlias cz accepted
koKoreanAlias kr accepted
zhChinese (Simplified)
jaJapanese

Format

The separator is a comma. Whitespace around each element is ignored when parsing; encoders should not emit it.

  • Numeric: 2,1639,198
  • Text (English): ability,smoke,board

All words of an address must come from the same wordlist. The language is conveyed separately (for example as a URL parameter: ?en=ability,smoke,board).

Word Matching

Decoders must compare words after applying the following normalization to both the input and the wordlist:

  1. Unicode normalization form NFKD.
  2. Conversion to lowercase.
  3. Removal of Latin combining diacritical marks (U+0300–U+036F).

As a result, matching ignores case and accents: Cojín, cojin and COJIN all decode to the same index. Japanese voiced sound marks (U+3099, U+309A) are outside that range and are preserved, since they change the word. This normalization produces no collisions in any of the supported wordlists.

Encoders output each word exactly as it appears in the wordlist.

7. Approximate Precision by Word Count

Each additional BGrid word subdivides the previous cell into 2048 smaller cells.
The values below show the average area per cell (Earth surface area divided by 2048L2048^L).

Note: Real cell area varies by latitude, because cells have equal angular size. Cells near the equator are larger than the average and cells shrink toward the poles. See the cell dimensions table below.

Metric (SI)

WordsCells Worldwide (2048L2048^L)Approx. Area per Cell
12,048249,058.59 km²
24,194,304121.61 km²
38,589,934,59259,380.20 m²
417,592,186,044,41628.99 m²

Imperial (US)

WordsCells Worldwide (2048L2048^L)Approx. Area per Cell
12,04896,162.06 mi²
24,194,30446.95 mi²
38,589,934,592639,163.11 ft² (14.67 acres)
417,592,186,044,416312.09 ft²

Cell Dimensions by Latitude

Approximate width × height of a single cell on the WGS84 ellipsoid:

WordsCell size (degrees)At the equatorAt 45°At 60°
15.625° × 5.625°626 × 622 km444 × 625 km314 × 627 km
20.17578° × 0.08789°19.6 × 9.7 km13.9 × 9.8 km9.8 × 9.8 km
30.0027466° × 0.0027466°306 × 304 m217 × 305 m153 × 306 m
40.000085831° × 0.000042915°9.6 × 4.7 m6.8 × 4.8 m4.8 × 4.8 m

8. Validation and Errors

Implementations must reject invalid input with an error rather than silently clamping or wrapping it. Clamping (step 3 of the encoding algorithm) applies only to points exactly on the outer boundary, never to out-of-range values.

InputValid valuesError when
Latitude ϕ\phiFinite number in [−90,90][-90, 90]Not a finite number, or outside the range
Longitude λ\lambdaFinite number in [−180,180][-180, 180]Not a finite number, or outside the range
Depth LLInteger ≥1\ge 1Not a positive integer
Index iki_kInteger in [1,2048][1, 2048]Not an integer, or outside the range
WordPresent in the selected wordlist after normalizationNot found

Error messages should state which input failed, its value, its position in the address when applicable, the valid range and by how much it is exceeded. For example:

  • Latitude 95.2° is out of range [-90, 90]: 5.2° above the maximum
  • Longitude -181.5° is out of range [-180, 180]: 1.5° below the minimum
  • Index 2049 at position 2 is out of range [1, 2048]: 1 above the maximum
  • Word "cojinn" at position 3 is not in the Spanish wordlist

9. Known Limitations

  • No locality across boundaries: two points a few metres apart on opposite sides of a cell boundary can have completely different addresses, sharing no common prefix.
  • No error detection: there is no checksum. A misheard or mistyped word still decodes to a valid, but different, location.
  • Polar distortion: cells near the poles become very narrow in longitude.