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', clamp=False, check=False)
¶
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'
|
clamp
|
bool
|
Project a point outside the domain onto its edge instead of raising. Off by default: a silently moved address is worse than a refused one. |
False
|
check
|
bool
|
Append a check character (see :func: |
False
|
Returns:
| Type | Description |
|---|---|
str
|
Code string, e.g. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If domain is unknown, or if the coordinates fall outside the domain's bounding box and clamp is false. |
Source code in src/yoro/codec.py
encode_for_country(lat, lon, country_code, precision=12)
¶
Encode a point using its country's domain, falling back worldwide.
The country-specific domains are bounding boxes, so a point can be
legitimately in a country and outside its box: border areas, enclaves,
offshore points, and countries covered by a combined extract. A country may
also have no domain at all. Either way the point stays addressable — this
falls back to the planet-wide "XX" domain instead of raising.
Prefer this over encode(lat, lon, domain=domain_for_country(cc))
whenever the coordinates are not known to sit inside the box: that form
raises, and every caller ends up reimplementing the same fallback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lat
|
float
|
Latitude in degrees. |
required |
lon
|
float
|
Longitude in degrees. |
required |
country_code
|
str | None
|
ISO 3166-1 alpha-2 code, e.g. |
required |
precision
|
int
|
Hilbert order; see :func: |
12
|
Returns:
| Type | Description |
|---|---|
str
|
Code string, in the country's domain when it fits, |
Example::
>>> encode_for_country(6.8, -5.3, "CI") # inside the box
'CI-NW64D'
>>> encode_for_country(64.1, -21.9, "CI") # Reykjavik is not
'XX-...'
Source code in src/yoro/codec.py
decode(code, check=False)
¶
Decode an Yoro string to GPS coordinates and cell bounds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
Yoro string, e.g. |
required |
check
|
bool
|
The last character of the body is a check character: verify it
and strip it before decoding. Use on codes produced by
|
False
|
Returns:
| Type | Description |
|---|---|
DecodedCode
|
Dict with keys: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the code format, length, or domain is invalid, if the check character does not match, or if the code addresses a cell outside the grid its length defines. |
Source code in src/yoro/codec.py
neighbors(code, check=False)
¶
Return up to 8 neighboring cell codes (edge/corner adjacency).
Codes on the domain boundary may return fewer than 8 neighbors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
Yoro string. |
required |
check
|
bool
|
The input carries a check character; verify it, and give every returned neighbour its own. Without this a checked code yields unchecked neighbours, which then fail to decode the same way. |
False
|
Source code in src/yoro/codec.py
resolution(p, domain='CI')
¶
Approximate spatial resolution in meters for Hilbert order p in domain.
Source code in src/yoro/codec.py
get_bounds(code, check=False)
¶
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": {...}}.
Raises:
| Type | Description |
|---|---|
ValueError
|
If domain is unknown, or if the requested area would produce more than max_cells cells (lower the precision or shrink the bounding box). |
Source code in src/yoro/codec.py
ranges(lat_min, lat_max, lon_min, lon_max, precision=12, domain='CI', max_ranges=None)
¶
Decompose a bounding box into code intervals for B-tree queries.
Where :func:cells_in_bounds enumerates every cell — and refuses past
max_cells — this returns the handful of intervals that contain them,
whatever the area.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lat_min
|
float
|
Southern edge of the box, in degrees. |
required |
lat_max
|
float
|
Northern edge of the box, in degrees. |
required |
lon_min
|
float
|
Western edge of the box, in degrees. |
required |
lon_max
|
float
|
Eastern edge of the box, in degrees. |
required |
precision
|
int
|
Hilbert order; snapped to the canonical precision. |
12
|
domain
|
str
|
ISO country code or |
'CI'
|
max_ranges
|
int | None
|
Coalesce until at most this many intervals remain, merging the closest pairs first. The result then covers some cells outside the box — filter on exact coordinates afterwards if that matters. |
None
|
Returns:
| Type | Description |
|---|---|
list[tuple[str, str]]
|
List of |
list[tuple[str, str]]
|
for |
Example::
>>> for lo, hi in ranges(12.60, 12.66, -8.03, -7.97, domain="ML"):
... cur.execute("SELECT * FROM pois WHERE code BETWEEN ? AND ?", (lo, hi))
Source code in src/yoro/codec.py
prefix_range(prefix_code, full_length)
¶
Return the full-code interval a truncated code covers.
Truncation has two possible readings, and they are not the same thing:
a. the index interval [d * 29^t, (d+1) * 29^t) — a connected segment
of the curve, exactly what LIKE 'prefix%' matches;
b. decoding the prefix as a short code — a cell at the canonical precision
of k - t, whose edges do not align with the finer grid.
This function implements (a).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix_code
|
str
|
Truncated code, e.g. |
required |
full_length
|
int
|
Body length k of the complete codes being matched. |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
str
|
range so it never spans codes :func: |
Source code in src/yoro/codec.py
check_char(body)
¶
Return the check character for a base-29 code body.
c = (sum_i w_i * v_i) mod 29 with distinct non-zero weights. Catches
every single-symbol substitution and every adjacent transposition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
str
|
Code body without the domain prefix and without a check
character, e.g. |
required |
Example::
>>> check_char("4H7A3B")
'R'
Source code in src/yoro/codec.py
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[PrecisionLevelInfo]
|
List of dicts with keys: |
list[PrecisionLevelInfo]
|
|
Source code in src/yoro/codec.py
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
domain_for_country(country_code)
¶
Map an ISO country code to an Yoro domain. Falls back to "XX".
domains_for(lat, lon)
¶
Return every country domain whose box contains a point, tightest first.
Deliberately plural. Domains are bounding boxes, and in West Africa they overlap heavily: Bamako (12.63, -8.00) sits inside Mali's box and inside Guinea's, and Guinea's is the smaller of the two — so "the smallest box containing the point" answers Guinea for Mali's capital. No rule over rectangles fixes that; only real borders would, and this package does not carry them.
So this hands back the candidates and lets the caller decide with whatever
it knows that boxes do not — a reverse geocode, a country column, the user's
own answer. When you already know the country, use
:func:encode_for_country instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lat
|
float
|
Latitude in degrees. |
required |
lon
|
float
|
Longitude in degrees. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Domain prefixes ordered by increasing box area, empty when no country |
list[str]
|
box fits. |
list[str]
|
makes it useless as a candidate and correct only as a fallback. |
Example::
>>> domains_for(12.63, -8.00)
['GN', 'ML']
Source code in src/yoro/codec.py
domain_of(code)
¶
Return the domain a code belongs to, without decoding it.
Cheaper than :func:decode when all you need is the domain — reading the
prefix costs a string split, while decoding walks the whole Hilbert curve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
A Yoro code, e.g. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The domain prefix, e.g. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the format is invalid or the domain is unknown. |
Example::
>>> domain_of("ci-4h7a3b")
'CI'
Source code in src/yoro/codec.py
anisotropy(domain='CI')
¶
Width-to-height ratio of a domain's cells on the ground (1.0 = square).
The curve's locality guarantees are stated in normalized distance; they only
carry over to metres when cells are roughly square. A domain drifting far
from 1.0 means "nearby code" and "nearby place" have started to come apart
along one axis — pick boxes such that
lat_range ~= lon_range * cos(mid_latitude).
Returns:
| Type | Description |
|---|---|
float
|
Ratio above 1.0 when cells are wider than tall. |