Skip to content

Core API Reference

Yoro Codec — Geographic addressing via 2D Hilbert curves.

Bijection between GPS coordinates and compact alphanumeric codes. Pure Python, zero external dependencies.

Theory: Paul Guindo, Altius Academy SNC.

encode(lat, lon, precision=12, domain='CI')

Encode GPS coordinates to an Yoro string.

Parameters:

Name Type Description Default
lat float

Latitude (WGS 84).

required
lon float

Longitude (WGS 84).

required
precision int

Hilbert order (higher = finer grid). Default 12.

12
domain str

ISO country code or "XX" for global.

'CI'

Returns:

Type Description
str

Code string, e.g. "CI-4H7A3B".

Raises:

Type Description
ValueError

If domain is unknown.

Source code in src/yoro/codec.py
def encode(lat: float, lon: float, precision: int = 12, domain: str = "CI") -> str:
    """Encode GPS coordinates to an Yoro string.

    Args:
        lat: Latitude (WGS 84).
        lon: Longitude (WGS 84).
        precision: Hilbert order (higher = finer grid). Default 12.
        domain: ISO country code or "XX" for global.

    Returns:
        Code string, e.g. ``"CI-4H7A3B"``.

    Raises:
        ValueError: If *domain* is unknown.
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'. Available: {list(DOMAINS.keys())}")

    dom = DOMAINS[domain]
    k = _code_length(precision)
    p = _canonical_precision(k)
    m = 1 << p

    x = min(m - 1, int((lon - dom["lon_min"]) / (dom["lon_max"] - dom["lon_min"]) * m))
    y = min(m - 1, int((lat - dom["lat_min"]) / (dom["lat_max"] - dom["lat_min"]) * m))
    x = max(0, x)
    y = max(0, y)

    d = _xy2d(p, x, y)
    code = _int_to_base29(d, k)

    return f"{domain}-{code}"

decode(code)

Decode an Yoro string to GPS coordinates and cell bounds.

Parameters:

Name Type Description Default
code str

Yoro string, e.g. "CI-4H7A3B".

required

Returns:

Type Description
dict

Dict with keys: lat, lon, precision, domain, bounds.

Raises:

Type Description
ValueError

If the code format or domain is invalid.

Source code in src/yoro/codec.py
def decode(code: str) -> dict:
    """Decode an Yoro string to GPS coordinates and cell bounds.

    Args:
        code: Yoro string, e.g. ``"CI-4H7A3B"``.

    Returns:
        Dict with keys: ``lat``, ``lon``, ``precision``, ``domain``, ``bounds``.

    Raises:
        ValueError: If the code format or domain is invalid.
    """
    if "-" not in code:
        raise ValueError("Invalid format: code must contain a dash (e.g. 'CI-4H7A3B')")

    prefix, base29_code = code.split("-", 1)
    prefix = prefix.upper()

    if prefix not in DOMAINS:
        raise ValueError(f"Unknown domain prefix: '{prefix}'")

    dom = DOMAINS[prefix]
    k = len(base29_code)
    p = _canonical_precision(k)
    m = 1 << p

    d = _base29_to_int(base29_code)
    x, y = _d2xy(p, d)

    lon = dom["lon_min"] + (x + 0.5) * (dom["lon_max"] - dom["lon_min"]) / m
    lat = dom["lat_min"] + (y + 0.5) * (dom["lat_max"] - dom["lat_min"]) / m

    bounds = _cell_bounds(x, y, p, dom)

    return {
        "lat": round(lat, 8),
        "lon": round(lon, 8),
        "precision": p,
        "domain": prefix,
        "bounds": bounds,
    }

neighbors(code)

Return up to 8 neighboring cell codes (edge/corner adjacency).

Codes on the domain boundary may return fewer than 8 neighbors.

Source code in src/yoro/codec.py
def neighbors(code: str) -> list[str]:
    """Return up to 8 neighboring cell codes (edge/corner adjacency).

    Codes on the domain boundary may return fewer than 8 neighbors.
    """
    if "-" not in code:
        raise ValueError("Invalid format")

    prefix, base29_code = code.split("-", 1)
    prefix = prefix.upper()

    if prefix not in DOMAINS:
        raise ValueError(f"Unknown domain prefix: '{prefix}'")

    k = len(base29_code)
    p = _canonical_precision(k)
    m = 1 << p

    d = _base29_to_int(base29_code)
    cx, cy = _d2xy(p, d)

    result: list[str] = []
    for dx, dy in [
        (-1, -1), (-1, 0), (-1, 1),
        (0, -1),           (0, 1),
        (1, -1),  (1, 0),  (1, 1),
    ]:
        nx, ny = cx + dx, cy + dy
        if 0 <= nx < m and 0 <= ny < m:
            nd = _xy2d(p, nx, ny)
            ncode = _int_to_base29(nd, k)
            result.append(f"{prefix}-{ncode}")

    return result

resolution(p, domain='CI')

Approximate spatial resolution in meters for Hilbert order p in domain.

Source code in src/yoro/codec.py
def resolution(p: int, domain: str = "CI") -> float:
    """Approximate spatial resolution in meters for Hilbert order *p* in *domain*."""
    dom = DOMAINS[domain]
    lat_range = dom["lat_max"] - dom["lat_min"]
    lon_range = dom["lon_max"] - dom["lon_min"]
    m = 1 << p
    dlat = lat_range / m
    dlon = lon_range / m
    lat_m = dlat * 111_000
    lon_m = dlon * 111_000 * math.cos(math.radians((dom["lat_min"] + dom["lat_max"]) / 2))
    return max(lat_m, lon_m)

get_bounds(code)

Return only the cell bounding box for code.

Source code in src/yoro/codec.py
def get_bounds(code: str) -> dict[str, float]:
    """Return only the cell bounding box for *code*."""
    return decode(code)["bounds"]

cells_in_bounds(lat_min, lat_max, lon_min, lon_max, precision=12, domain='CI', max_cells=2000)

Return all Hilbert cells that intersect a geographic bounding box.

Each item is {"code": "CI-...", "bounds": {...}}. Returns an empty list if the cell count would exceed max_cells.

Source code in src/yoro/codec.py
def cells_in_bounds(
    lat_min: float,
    lat_max: float,
    lon_min: float,
    lon_max: float,
    precision: int = 12,
    domain: str = "CI",
    max_cells: int = 2000,
) -> list[dict]:
    """Return all Hilbert cells that intersect a geographic bounding box.

    Each item is ``{"code": "CI-...", "bounds": {...}}``.
    Returns an empty list if the cell count would exceed *max_cells*.
    """
    domain = domain.upper()
    dom = DOMAINS.get(domain)
    if not dom:
        return []

    k = _code_length(precision)
    p = _canonical_precision(k)
    m = 1 << p

    lat_range = dom["lat_max"] - dom["lat_min"]
    lon_range = dom["lon_max"] - dom["lon_min"]
    lat_step = lat_range / m
    lon_step = lon_range / m

    y_min = max(0, int((lat_min - dom["lat_min"]) / lat_step))
    y_max = min(m - 1, int((lat_max - dom["lat_min"]) / lat_step))
    x_min = max(0, int((lon_min - dom["lon_min"]) / lon_step))
    x_max = min(m - 1, int((lon_max - dom["lon_min"]) / lon_step))

    count = (x_max - x_min + 1) * (y_max - y_min + 1)
    if count > max_cells or count <= 0:
        return []

    cells: list[dict] = []
    for y in range(y_min, y_max + 1):
        for x in range(x_min, x_max + 1):
            d = _xy2d(p, x, y)
            cells.append({
                "code": f"{domain}-{_int_to_base29(d, k)}",
                "bounds": {
                    "lat_min": dom["lat_min"] + y * lat_step,
                    "lat_max": dom["lat_min"] + (y + 1) * lat_step,
                    "lon_min": dom["lon_min"] + x * lon_step,
                    "lon_max": dom["lon_min"] + (x + 1) * lon_step,
                },
            })
    return cells

precision_levels(domain='CI', max_code_length=10)

Return all canonical precision levels for a domain.

A canonical precision is a Hilbert order p that produces a distinct code length k. Because codes use base-29, the mapping from p to k is k = ceil(2p * log2 / log29). Several consecutive values of p map to the same k — only the highest p for each k is canonical, i.e. the one that fully exploits the address space of k characters.

Parameters:

Name Type Description Default
domain str

ISO country code (affects resolution in meters).

'CI'
max_code_length int

Stop after this many characters (default 10 → ~4 cm).

10

Returns:

Type Description
list[dict]

List of dicts with keys: precision, code_length, grid_size,

list[dict]

total_cells, resolution_m.

Source code in src/yoro/codec.py
def precision_levels(domain: str = "CI", max_code_length: int = 10) -> list[dict]:
    """Return all canonical precision levels for a domain.

    A canonical precision is a Hilbert order *p* that produces a distinct
    code length *k*.  Because codes use base-29, the mapping from *p* to *k*
    is ``k = ceil(2p * log2 / log29)``.  Several consecutive values of *p*
    map to the same *k* — only the highest *p* for each *k* is canonical,
    i.e. the one that fully exploits the address space of *k* characters.

    Args:
        domain: ISO country code (affects resolution in meters).
        max_code_length: Stop after this many characters (default 10 → ~4 cm).

    Returns:
        List of dicts with keys: ``precision``, ``code_length``, ``grid_size``,
        ``total_cells``, ``resolution_m``.
    """
    if domain not in DOMAINS:
        raise ValueError(f"Unknown domain: '{domain}'")

    levels: list[dict] = []
    for k in range(1, max_code_length + 1):
        p = _canonical_precision(k)
        grid = 1 << p
        res = resolution(p, domain=domain)
        levels.append({
            "precision": p,
            "code_length": k,
            "grid_size": grid,
            "total_cells": grid * grid,
            "resolution_m": round(res, 4),
        })
    return levels

snap_precision(p)

Return the canonical precision that p actually resolves to.

Because the code length is quantized to whole base-29 characters, several values of p produce the same grid. This function shows which canonical precision is effectively used.

Example::

>>> snap_precision(18)
19          # p=18 and p=19 both use 8-character codes
>>> snap_precision(15)
17          # p=15 and p=16 both snap up to canonical p=17
Source code in src/yoro/codec.py
def snap_precision(p: int) -> int:
    """Return the canonical precision that *p* actually resolves to.

    Because the code length is quantized to whole base-29 characters,
    several values of *p* produce the same grid.  This function shows
    which canonical precision is effectively used.

    Example::

        >>> snap_precision(18)
        19          # p=18 and p=19 both use 8-character codes
        >>> snap_precision(15)
        17          # p=15 and p=16 both snap up to canonical p=17
    """
    k = _code_length(p)
    return _canonical_precision(k)

domain_for_country(country_code)

Map an ISO country code to an Yoro domain. Falls back to "XX".

Source code in src/yoro/codec.py
def domain_for_country(country_code: str | None) -> str:
    """Map an ISO country code to an Yoro domain. Falls back to ``"XX"``."""
    code = country_code.upper() if country_code else "CI"
    return code if code in DOMAINS else "XX"