Repository navigation
Take ChamberlainDuquetteArea's rings across the antimeridian the short way around - #1631
Closed
flight1973 wants to merge 8 commits into
Closed
flight1973 wants to merge 8 commits into
flight1973 wants to merge 8 commits into
Conversation
Each edge's change in longitude was taken as written, so an edge from 179° to -179° ran 358° the long way: a 1° square across the antimeridian measured minus the area of the rest of its band of latitude (-4.4 million km²), and a ring winding around a pole measured zero. An edge written across more than 180° is now taken the short way, as GeodesicArea takes it, by correcting its share of the sum, so a ring with no such edge gives bit for bit what it did. A ring that then winds around a pole gets 2πR² per turn and the smaller of the two sides it splits the Earth into, negative when that side is on the ring's right (as GeodesicArea's signed area is). An edge written from -180° to 180° now spans nothing.
An edge written across exactly 180° is meant to keep the direction it is written in, but its span was compared in radians, where 180° can round either side of π, so depending on its longitudes such an edge could be taken the other way round. Spans are now compared in degrees, where an edge across exactly 180° is exactly 180°. A ring that splits the Earth into halves, such as one along the equator, now gets half the Earth, positive, whichever way round it is written: the result is in (-earth/2, earth/2]. The docs and CHANGES.md now say what a box wider than 180° of longitude measures (the narrower box the other way round) and mark the change as breaking.
flight1973
marked this pull request as draft
November 2, 2026 23:55
A Rect spans from its minimum longitude east to its maximum, however wide, but it was measured as a polygon, whose edges are now each taken the short way around: the whole world measured nothing, and a box from -100° to 100° measured the narrower box the other way round. A Rect is now measured directly, as it was before. A ring with an edge written across more than 180° of longitude was summed as written and then corrected by whole turns. The correction cancelled terms of the order of 2π, which cost precision for small polygons across the antimeridian (an f32 box 0.01° wide measured nothing) and gave believable but wrong areas, or NaN, for longitudes written far out of range. Such a ring is now summed edge by edge, with each change in longitude reduced exactly and the winding counted from the reduced changes. A ring with no such edge takes the same sum as before, bit for bit, in a single pass. An edge written across 540° (or 180° plus any whole number of turns) now keeps the direction it is written in, as one across 180° does.
… written An edge from -180° to 180° along a parallel runs all the way round it, as in a box spanning the world or a polygon clipped along a parallel, and an edge along a pole goes nowhere whatever its change in longitude. Taking either the short way made a world box measure nothing, a polygon clipped to Web Mercator's limit gain the cap beyond it, and a ring closed along a pole wind around the other pole and measure its smaller side. Both are taken as written again, and a ring whose only edges wider than 180° are such edges takes the same sum as before, bit for bit. An edge with an end more than a million degrees out isn't a longitude, so its ring is taken as written, as before, rather than reduced to a plausible area. The reduction no longer uses `%`, whose cost grows with the size of its operands, and the turns taken off each edge are counted as an integer, so a ring's winding no longer depends on rounding. The sum for a ring with an edge taken the short way takes its latitudes' sines relative to the first vertex's, so a small polygon across the antimeridian keeps its precision in f32 as well as f64, whatever its shape.
Chamberlain and Duquette's sum treats an edge as a straight line in longitude and the sine of latitude, along which an edge along a parallel is exact: a box is as wide as it is written, and the pieces of a polygon clipped along parallels add up to it. Clippers write such edges wider than 180°, and taking them the short way made a strip from 57°W to 140°E, as a clip leaves it, measure some fifty times its area, and Antarctica clipped to Web Mercator's limit measure more than Antarctica. An edge along a parallel (to within a few units in the last place) is taken as written again, which covers those along a pole and from -180° to 180°, and a `Rect` is measured as its polygon again. So a box across the antimeridian written with only its corners is as wide as it is written, as it always was. A polygon with a ring winding around a pole is reduced to the smaller side once, after its holes are subtracted, rather than ring by ring, so a band between two rings around a pole measures the band. A ring with any longitude more than a million degrees out is taken as written throughout. The change in longitude of an edge taken the short way is taken from its ends rather than from the change as written, which has rounded to the precision of a value near a whole turn.
…ritten Deciding edge by edge, a ring that crossed the antimeridian once along a parallel and once off one took the first the long way and the second the short way, so it wound around a pole and measured about a polar cap: an island whose coordinates are rounded, say, or a polygon clipped along a parallel across the antimeridian. Now a ring with an edge wider than 180° off a parallel takes each of its edges wider than 180° the short way, except along a pole, and any other ring is taken as written. An edge is along a parallel to within a few units in the last place of its latitude rather than of 360°, which in f32 was several meters, and along a pole to within 1e-9°. A polygon whose exterior doesn't wind around a pole now cuts the smaller side out of each of its holes that does, rather than reducing the whole polygon to its smaller side, so the world less Antarctica measures the world less Antarctica. A total too far out for its rings' winding to explain, as from a ring taken as written, is left as it is rather than reduced to a plausible area. A longitude beyond ±720°, rather than a million degrees, is too far out to be one.
… with its sign An edge ran along a parallel to within a few units in the last place of its latitude, which is nothing at the equator: a band from -180° to 180° with a corner 1e-17° below it, or with one corner through a round trip to Web Mercator, was taken the short way and measured nothing. The tolerance is now at least 1e-9°, and a change in longitude is 180°, or more than 180°, by the same measure, so a change of 180° that computes to 180.00000000000003, as in data written from 0° to 360°, keeps its direction. A ring's winding is now counted with its sign, so a polygon whose holes wind it back, such as a band between two rings around a pole, measures what it encloses rather than its smaller side. And each ring's area is checked against its own winding, so a hole taken as written is no longer reduced to a plausible area by an exterior that winds many times.
In f32, 180° plus 1e-9° is 180°, so an edge written across 180° whose change in longitude computes to a unit in the last place more, as about one in ten do in data written from 0° to 360°, was taken the other way round; and a tolerance of a few units in the last place of the latitude was next to nothing near the equator, so a band with a corner through a round trip to Web Mercator measured nothing. An edge now runs along a parallel, or a pole, to within 1e-9° or the type's precision near 360° if that is coarser, and a change in longitude is 180° to within that or the precision of the longitudes. In f64 neither is more than 1e-9°, so nothing changes there. A hole winding around a pole in an exterior that doesn't now cuts out the smaller of its sides whichever way it winds, rather than adding it when it lies on the hole's right.
flight1973
marked this pull request as ready for review
November 3, 2026 02:44
Member
|
Please re-open with a description written for human consumption. |
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ChamberlainDuquetteAreatakes each edge's change in longitude as written, so a polygon that crosses the antimeridian without being cut there gets a wildly wrong area. For example:measures -4,435,868 km² on
main. The same polygon written with 181° instead of -179° measures 24,781 km². A ring around a pole that isn't closed along the pole, such as an uncut Antarctica coastline, comes out wrong too.With this change, a ring that has an edge spanning more than 180° that isn't along a parallel takes its wide edges the short way around, as
GeodesicAreadoes, and a ring that then winds around a pole gets the smaller side. Rings without such an edge are computed exactly as before, so boxes,Rects, latitude bands and polygons clipped along parallels are unchanged, bit for bit. On Natural Earth data the results are unchanged as published and when clipped; rotated so that polygons cross the antimeridian, those polygons now come out right, with no regressions.This is a breaking change for rings with a wide edge that isn't along a parallel, including convex hulls or simplifications done in longitude and latitude that span more than 180°. The details are in the rustdoc and
CHANGES.md.Separately, holes wound opposite to their exterior are added instead of subtracted. That's an existing bug, not touched here; I'll open an issue for it.
AI disclosure: I used an LLM (Claude) to adapt work we had been doing for RustGIS to geo. It drafted the fix and the tests, which I reviewed.
CHANGES.mdif knowledge of this change could be valuable to users.