@gkucmierz/geo-number
v1.0.3
Published
High-precision geographic coordinate hashing engine using the HEALPix algorithm. Encodes exact Latitude and Longitude to equal-area mathematical String/BigInt representations bounding global precision up to 1m^2.
Maintainers
Readme
@gkucmierz/geo-number
High-precision geographic coordinate hashing engine utilizing the HEALPix (Hierarchical Equal Area isoLatitude Pixelization) algorithm.
geo-number mathematically encodes exact Latitude and Longitude pairs into single large BigInt identifiers (hashes), guaranteeing equal-area surface projections. It natively supports extreme resolutions beyond order 52, bounding global planetary precision down to 1 m² without suffering from standard JSON float/32-bit bitshift precision bottlenecks.
Description
Unlike traditional Geohashing (Z-ordered curves) where precision grids distort severely depending on their geographic position (e.g. stretching at poles), geo-number relies on HEALPix tessellation to guarantee that every single hash area globally maintains exactly the same square area.
This library serves as a bulletproof engine to compress coordinate coordinates into raw deterministic IDs or to resolve encoded tokens back to a center point.
Installation
npm install @gkucmierz/geo-numberFeatures
- Extreme Scaling: Safely implements HEALPix Order 52 bounds (
nsidescaling up to10^15). - Equal-Area Hash Tessellation: Guarantees standard spherical dimensions regardless of origin geometry.
- Floating-Point Limits Avoidance: Overrides traditional JS operators with custom
BigIntMath logic bounds. - ES Modules: Fully modern JS build natively supporting Typescript environments and modern Web Bundlers.
Usage
1. Encoding Coordinates (Lat / Lng -> BigInt)
Converts a geographic point to a HEALPix grid BigInt cell ID depending on the provided resolution order.
import { encode, decode } from '@gkucmierz/geo-number';
// Parameters: lat, lng, resolution order (default is very high stringency: 52n)
const lat = 52.2297;
const lng = 21.0122;
const hashId = encode(lat, lng, 30n);
console.log(hashId); // e.g. 195843475988225588n2. Decoding a Hash (BigInt -> Lat / Lng)
Resolves a previously encoded geo-number token back into its exact geometric face center coordinate over the given order.
import { encode, decode } from '@gkucmierz/geo-number';
// Parse BigInt hash directly
const hashId = 195843475988225588n;
// Decode with matching initialization order
const point = decode(hashId, 30n);
console.log(`Latitude: ${point.lat}, Longitude: ${point.lng}`);Precision Scales / Order Sizes
The strictness of compression relies on the specific order scaling (where total global sphere regions = 12 * 2^(2 * order)). In standard operations resolving typical Earth representations (Area ~ 510,072,000 km²):
- Order 15: ~1,820 m²
- Order 20: ~1.73 m²
- Order 23: ~0.60 m² (Half-meter sq - Ideal for Street Level)
- Order 24: ~0.15 m²
- Order 26: ~0.009 m² (~1 dm²)
- Order 52: Absolute JS
BigIntLibrary Boundary (Extremely deep Sub-millimeter scales natively supported without overflow).
The library inherently restricts coordinate floats to physical boundaries (Lat [-90, 90], Lng [-180, 180]). Values exceeding this sphere will securely clamp or normalize wrap.
Dictionary Encoding & Checksum Tradeoffs
When mapping these BigInt identifiers to a dictionary of words (e.g. BIP39 where each word provides exactly 11 bits of entropy), a 5-word sequence yields exactly 55 bits of payload payload.
The specific order you choose directly determines how many of those 55 bits are consumed by the geographic ID, and how many are reserved for a checksum (which detects user spelling/dictation errors).
Here is a complete mathematical breakdown analyzing the UX tradeoff between Order 23 and Order 24 inside a 5-word encoding system:
const EARTH_AREA_M2 = 510.072e12; // sq meters
const BITS_PER_WORD = 11;
const TOTAL_WORDS = 5;
const TOTAL_BITS = TOTAL_WORDS * BITS_PER_WORD; // 55 bits total
function evaluateTradeoff(order) {
// Total HEALPix pixels globally for the given order: 12 * (4^order)
const totalPixels = 12 * Math.pow(4, order);
const areaSqMeters = EARTH_AREA_M2 / totalPixels;
const payloadBits = Math.ceil(Math.log2(totalPixels));
const checksumBits = TOTAL_BITS - payloadBits;
// Chance that a completely random typo accidentally matches a valid checksum
const falsePositiveRate = 1 / Math.pow(2, checksumBits);
const errorDetectionRate = (1 - falsePositiveRate) * 100;
return {
areaSqMeters: areaSqMeters.toFixed(2),
payloadBits,
checksumBits,
errorDetectionRate: errorDetectionRate.toFixed(2) + '%'
};
}
console.log("Order 23:", evaluateTradeoff(23));
// -> { areaSqMeters: "0.60", payloadBits: 50, checksumBits: 5, errorDetectionRate: "96.88%" }
console.log("Order 24:", evaluateTradeoff(24));
// -> { areaSqMeters: "0.15", payloadBits: 52, checksumBits: 3, errorDetectionRate: "87.50%" }Conclusion: Order 23 is the optimal engineering choice. By sacrificing sub-meter precision down to 0.60 m² (still equivalent to a paving stone, well within the boundary limits of phone GPS accuracy), the system retains a robust 5-bit checksum. This guarantees a ~96.9% native rejection rate for user typos and dictation mistakes, whereas Order 24 would quietly accept false addresses in 1 out of 8 typos.
