A polygon crossing the antimeridian is usually written wrapped: 179.9 then
-179.9. Read literally — which is what both coverage twins now do — that edge
runs 359.8 degrees the WRONG way round the world, and the polygon is its own
complement. Measured on global05: 7,196 cells instead of 4.
Arguments
- ring
a two-column matrix (or anything
as.matrix()gives one from) with longitude in column 1- x
an
sf,sfcorsfgPOLYGON / MULTIPOLYGON
Value
the same matrix with column 1 unwrapped
for unwrap_polygon(), the same object with every ring unwrapped
Details
The fix is one explicit rule, applied at the INPUT boundary and nowhere else.
Walking the ring, whenever consecutive vertices differ by more than 180 degrees
of longitude, carry -/+360 onward (the shortest-path convention). The first
vertex is never moved, so the ring keeps whichever frame it arrived in; only the
edges are made short. The result may leave [-180, 180] — that is the point, and
it is what the g1 codec stores and what cells_in_polygon_grid() expects.
unwrap_polygon() applies the rule to every ring of a POLYGON or MULTIPOLYGON,
each ring independently: a hole is a closed ring of its own and carries its own
crossings, and a multipolygon part on each side of the line must stay on its own
side rather than being dragged across by its neighbour.
Where this runs
At every input boundary — an upload, a drawn place, place_encode(), the
sf-facing wrappers such as cells_in_polygon() — and never inside coverage.
cells_in_polygon_grid() reads coordinates literally and guesses nothing; that is
the whole reason this is a separate, exported, separately-fixtured function with a
TypeScript twin (unwrapRing()), rather than a heuristic buried in the geometry.
The limit
A ring that genuinely spans more than 180 degrees of longitude cannot be expressed wrapped: every one of its long edges is indistinguishable from a crossing, and the shortest-path convention will turn it inside out. Such a ring must arrive already unwrapped. This is a property of the wrapped representation, not of this implementation.