Skip to content

Fix precision loss in cellAreaRads2 for cells crossing the antimeridian - #1274

Open
thevar1able wants to merge 2 commits into
uber:masterfrom
thevar1able:fix-cagnoli-antimeridian
Open

thevar1able wants to merge 2 commits into
uber:masterfrom
thevar1able:fix-cagnoli-antimeridian

Conversation

@thevar1able

Copy link
Copy Markdown

Since #1101, cellAreaRads2 adds up a term per cell edge (cagnoli in area.c). For an edge that crosses ±180°, the raw longitude difference is close to ±2π. The real gap between the two vertices is tiny, and at that magnitude it gets lost to floating-point rounding before sin and cos are applied. Nothing cancels the error, so cells that straddle the antimeridian come out too small. Compared with a neighbouring cell, a straddling cell is about 0.07% too small at res 13, 0.4% at res 14 and 2.5% at res 15. This also affects cellAreaKm2 and cellAreaM2, and geoLoopAreaRads2 and the other polygon area helpers. Releases before #1101 used a different formula and don't have this problem.

The fix shifts both longitudes to the same side of the antimeridian before subtracting, so the subtraction is between two nearby values. sin and cos repeat every 2π, so the result is mathematically the same. Edges that don't cross the antimeridian take the old path unchanged.

Tests:

  • cell_area_antimeridian: three pairs of cells at res 13–15, each a straddling cell next to one that doesn't straddle. Their areas must agree to within 1e-5.
  • cell_area_antimeridian_rotation: at every resolution, cells along ±180° must keep their area when their boundary is shifted 180° in longitude, to within 1e-6. Shifting around the polar axis can't change an area, so this needs no reference values. The worst result on fixed code is 3e-8 at res 15; unfixed code is off by up to 7.6e-2.
  • antimeridianTriangle: a small triangle across ±180° must have the same area as the same triangle across 0°. This uses a triangle and not a rectangle on purpose: a rectangle's two crossing edges have identical longitude differences, so their rounding errors cancel and the test passes even without the fix.

Each new test fails without the fix. The existing exhaustive area tests still pass. They only go up to res 4, where the error is too small for them to see, which is why nothing caught this.

This was found and fixed in ClickHouse's fork (ClickHouse#13, reported in ClickHouse/ClickHouse#124447). This PR ports that fix and adds the rotation and triangle tests.

Related: #1101, #1108

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

An error occurred during the review process. Please try again later.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 07d1baa5-313f-4b5c-9273-1500c901b7ec
📥 Commits

Reviewing files that changed from the base of the PR and between 28d83cd and 2194649.

📒 Files selected for processing: 4
  • CHANGELOG.md
  • src/apps/testapps/testGeoLoopArea.c
  • src/apps/testapps/testH3CellArea.c
  • src/h3lib/lib/area.c

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Walkthrough

The area calculation now adjusts longitude differences for edges that cross the antimeridian. New tests compare loop and cell areas across the antimeridian and after rotating cell boundaries.

Changes

Area calculation precision

Layer / File(s) Summary
Adjust antimeridian longitude differences
src/h3lib/lib/area.c
cagnoli recomputes longitude differences when their magnitude exceeds π, shifting each longitude before subtraction.
Test area calculations across the antimeridian
src/apps/testapps/testGeoLoopArea.c, src/apps/testapps/testH3CellArea.c, CHANGELOG.md
Tests compare equivalent loop areas, adjacent cell areas, and areas before and after a 180° longitude rotation. The changelog describes the precision fix.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 21946

This change improves the precision of area calculations for cells and loops that cross the antimeridian. No merge-blocking issue was found.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 3 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the main change: fixing precision loss in cellAreaRads2 for antimeridian-crossing cells.
Description check Passed The description directly explains the precision issue, the implementation approach, affected APIs, regression tests, and expected results.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 3 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thevar1able
thevar1able force-pushed the fix-cagnoli-antimeridian branch from 2194649 to 94b48e8 Compare October 19, 2026 16:27
@CLAassistant

CLAassistant commented Oct 19, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 99.758%. remained the same — thevar1able:fix-cagnoli-antimeridian into uber:master

justinhwang added a commit to uber/h3-go that referenced this pull request Oct 21, 2026
cagnoli subtracted the raw longitudes of an edge's endpoints. For an edge
crossing +-180 degrees the difference is close to +-360 and the true, tiny
longitude step is lost to the rounding of a value that large, so cells
straddling the antimeridian came out too small: 1e-8 relative at res 7,
0.1% at res 13 and 9% at res 15. Shifting both longitudes to the same side
of the antimeridian before subtracting keeps the subtraction between two
nearby values; sin and cos are 2pi-periodic, so nothing else changes. This
is upstream uber/h3#1274, which the pinned release does not yet contain.

The conformance suite could not see the defect: its seeded sample has
straddling cells only at resolutions 0 and 1, where the loss is far below
tolerance. The generator now carries the upstream change as a second patch
and writes floats/curated.jsonl, the upstream test pairs at res 13 to 15
plus the cell containing (lat, 180) at every resolution for three
latitudes, which the floats/cells checks run. The fifteen straddling res 0
and 1 cells already in floats/cells.jsonl move by at most 4e-14 relative;
every other file, the digests included, is byte for byte unchanged.

Three tests port the upstream ones: straddling cells agree with their
non-straddling neighbours, a cell on the antimeridian keeps its area when
rotated onto the prime meridian, and a small triangle across +-180 has the
area of the same triangle across 0. All three fail without the shift.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
justinhwang added a commit to uber/h3-go that referenced this pull request Oct 21, 2026
cagnoli subtracted the raw longitudes of an edge's endpoints. For an edge
crossing +-180 degrees the difference is close to +-360 and the true, tiny
longitude step is lost to the rounding of a value that large, so cells
straddling the antimeridian came out too small: 1e-8 relative at res 7,
0.1% at res 13 and 9% at res 15. Shifting both longitudes to the same side
of the antimeridian before subtracting keeps the subtraction between two
nearby values; sin and cos are 2pi-periodic, so nothing else changes. This
is upstream uber/h3#1274, which the pinned release does not yet contain.

The conformance suite could not see the defect: its seeded sample has
straddling cells only at resolutions 0 and 1, where the loss is far below
tolerance. The generator now carries the upstream change as a second patch
and writes floats/curated.jsonl, the upstream test pairs at res 13 to 15
plus the cell containing (lat, 180) at every resolution for three
latitudes, which the floats/cells checks run. The fifteen straddling res 0
and 1 cells already in floats/cells.jsonl move by at most 4e-14 relative;
every other file, the digests included, is byte for byte unchanged.

Three tests port the upstream ones: straddling cells agree with their
non-straddling neighbours, a cell on the antimeridian keeps its area when
rotated onto the prime meridian, and a small triangle across +-180 has the
area of the same triangle across 0. All three fail without the shift.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants