landcheck: offline land/sea lookup (a Trifold library)
landcheck: is this point on land or in the sea?
An offline lookup library built on the Trifold grid. Thanks to exact<br>aperture-4 nesting, the level-10 grid (~7 km cells) classified against Natural Earth<br>collapses into a 182 KB dataset that answers anywhere on Earth in microseconds,<br>with a confidence value for every answer. Python and JavaScript give identical results.<br>This page runs the real JS library in your browser ; the dataset is embedded right<br>in this HTML file.
Try it on the map
Interactive demo
Load sample points or your own file (CSV lon,lat or GeoJSON points), and<br>every point is classified in your browser by the bundled library, with no server<br>and no network call per lookup. The lookups-per-second figure is measured tightly around<br>the classification loop on your machine (map rendering and file parsing excluded),<br>so it is the real library throughput. Use the 100k-random button for a stable number.
Controls
Sample points
World cities + tricky spots<br>1k random<br>10k random<br>100k random
Your own points
Open CSV / GeoJSON…
CSV: lon,lat[,name] per line (or a header naming<br>lat/lon columns in either order). GeoJSON: any<br>FeatureCollection of Points. Files stay on your machine.
OSM coastal refinement
exact OSM polygon test wherever the coastline crosses a cell<br>(downloads once)<br>Off: coastal answers use the bundled<br>land-area fraction. On: near-exact coastline. Watch how the counts,<br>confidence and lookup rate change.
Debug layers
source coastline (NE , follows the<br>refinement setting)<br>Click anywhere on the map to see the<br>level-10 triangle and its classification.
Projection
Globe<br>Flat
land: certain (confidence 1.0)
coast: mixed cell
sea: certain (confidence 1.0)
answer flipped by OSM refinement
Loading dataset…
Click any classified point for its full answer:<br>cell address (computed on the fly for sea points, whose cells are not stored), kind,<br>confidence and land fraction. Note the Natural Earth 1:50m caveats: lakes count as land<br>and islets below its resolution are missing. Switching on the OSM coastal<br>refinement makes OSM authoritative in cells crossed by either source coastline. Try the<br>cities sample with it on and off and compare the answers near coasts.
User guide
JavaScript (browser or Node)
import { LandCheck } from "./landcheck.mjs";
// Node: bundled file · browser: fetch the 182 KB dataset<br>const lc = await LandCheck.fromFile(); // Node<br>const lc = await LandCheck.fromUrl("landsea_L10.tfls"); // browser
lc.isLand(24.7536, 59.437); // true (lon, lat)<br>lc.check(-0.1276, 51.5072);<br>// { land: true, kind: 'land', confidence: 1,<br>// landFraction: 1, cell: 'TFA95BM', refined: false }
Python (stdlib only)
from landcheck import LandCheck
lc = LandCheck() # bundled data<br>lc.is_land(24.7536, 59.4370) # True<br>lc.check(-0.1276, 51.5072)<br># LandResult(land=True, kind='land', confidence=1.0,<br># land_fraction=1.0, cell='TFA95BM', refined=False)
# vectorised: ~2.8 µs/point with numpy<br>lc.is_land_batch(lons, lats)
What the answer means
kindmeaninglandconfidence<br>land cell wholly inside landtrue1.0<br>sea cell absent from the datasetfalse1.0<br>coast mixed cell; bundled land-area fraction decides<br>fraction ≥ 0.5max(f, 1−f)<br>coast + refineddecided by the optional OSM polygon layer<br>exact0.99
Measured accuracy: 99.82% agreement with exact polygon containment on<br>30,000 uniform random points. The land and sea answers were 100%<br>correct; all residual error lives in coast answers, which self-report lower<br>confidence.<br>With the OSM refinement loaded, coastal answers reach 99.95%.
Command line
$ python landcheck/python/landcheck.py 24.7536 59.4370<br>LAND kind=land confidence=1.000 land_fraction=1.0 cell=TFAVKGR refined=False
Technical info
Canonical index Any Trifold cell at level ≤ 10 maps to<br>addr64 >> 39, a 25-bit integer where a level-l cell covers exactly<br>410−l consecutive indices. The whole classification becomes run-length<br>intervals.
TFLS format · 182 KB 153,884 runs as<br>varint(gap), varint(len·2|coastal) + a 4-bit land fraction per coastal<br>cell, zlib-compressed. Level-agnostic: the same tooling serves an L8 (~30 KB) or<br>L12 (~3 MB) variant.
Lookup path Pure-float point location (no dependencies,<br>bit-identical to the SDK) descends 10 subdivision levels, then one binary search over<br>the run starts. ~0.8 µs in Node, ~13 µs in pure Python, ~2.8 µs batched with numpy.
OSM refinement · TFLR OSM simplified land polygons clipped<br>to every cell crossed by either source coastline, quantized to a cell-local 16-bit grid<br>(~0.1 m), with zigzag-varint rings and the even-odd rule. The OSM polygon test can<br>override Natural Earth land, sea or fraction answers in those cells.
Full documentation, build scripts (build.py,<br>refine_build.py) and the cross-language test suite live in<br>landcheck/ on GitHub.<br>Roadmap: country detection with the same run-length + clipped-border approach, an L12<br>variant, published pip/npm packages.
Benchmark: Trifold vs SQL spatial engines
Same job for...