Skip to content

Add S2Earth #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Add S2Earth #191

wants to merge 2 commits into from

Conversation

flwyd
Copy link
Collaborator

@flwyd flwyd commented Jun 27, 2025

This is a copy of the google3 implementation, which was not included in previously because it lived elsewhere in the source tree. References to other files in google3 have been removed from comments.

Fixes #151

This is a copy of the google3 implementation, which was not included in
previously because it lived elsewhere in the source tree.  References to
other files in google3 have been removed from comments.
@flwyd flwyd requested a review from panmari June 27, 2025 01:25
earth/earth.go Outdated

// LowestAltitude is the altitude of the lowest known point on Earth,
// the Challenger Deep, below the surface of the spherical earth.
LowestAltitude = -10.898 * unit.Kilometer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wikipedia says: 10,920 ± 10 m

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I assume the same consistency with C++/Java comment applies here.

Unfortunately the CL that added these provided no context or source.

There's a separate can of worms as to whether we should update these values to better ones. This would break a lot of tests at Google and probably in the rest of the world, but is maybe possible in the age of LLMs.

Copy link
Collaborator Author

@flwyd flwyd Jun 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see a couple references to LowestAltitude across all three languages in google3, so updating this might be feasible. I've added a sentence to the comment explaining the value could change. I'd prefer not to make that change right now, though.

earth/earth.go Outdated

// HighestAltitude is the altitude of the highest known point on Earth,
// Mount Everest, above the surface of the spherical earth.
HighestAltitude = 8.846 * unit.Kilometer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wikiL: 8,848.86 m

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny enough, someone updated C++ and Java S2Earth values in 2019 but missed Go. I've updated the Go value to match (8848 meters, no fraction) and sent a CL to fix the one affected test in google3. Also added a comment that the value may change.


// LengthFromPoints returns the distance between two points on the spherical
// earth's surface.
func LengthFromPoints(a, b s2.Point) unit.Length {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be call LengthBetweenPoints?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The s2 package uses the "From" naming convention for most conversions; I think the predictability here is better than the slight improvement in terminology.

// of 0 degrees is north, and it increases clockwise (90 degrees is east, etc).
//
// If a == b, a == -b, or a is one of the Earth's poles, the return value is
// undefined.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay if B is one of the poles, just as long as A is not a pole?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, bearing to a pole is well defined. We should have a test for this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are "Towards north pole" and "Towards south pole" tests.

earth/earth.go Outdated
func haversine(radians float64) float64 {
sinHalf := math.Sin(radians / 2)
return sinHalf * sinHalf

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra blank line

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

{90, 0, 90, 0, 0 * unit.Meter},
{-37, 25, -66, -155, 8562022.790666264 * unit.Meter},
{0, 165, 0, -80, 12787436.635410652 * unit.Meter},
{47, -127, -47, 53, 20015118.077688109 * unit.Meter},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the user chooses values > +/-180 +/-90 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test for |longitude| ≥ 180. Latitude above 90° isn't conceptually valid, so garbage in garbage out.

}

func TestAreaFromSteradians(t *testing.T) {
const earthArea = 6371.01 * 6371.01 * math.Pi * 4 * unit.SquareKilometer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you reference Radius value here instead of copying the 6371.01 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

{s2.AvgAreaMetric.Value(20), 77.31706517582228 * unit.SquareMeter}, // average area of level 20 cells
{s2.AvgAreaMetric.Value(30), 73.73529927808979 * unit.SquareMillimeter}, // average area of level 30 cells
{s2.PolygonFromLoops([]*s2.Loop{s2.EmptyLoop()}).Area(), 0 * unit.SquareMeter},
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function mentions "The value will be between 0 and 4 * math.Pi if a does not exceed the area of the Earth."

Should there be any sanity bounds checks in the function to ensure its capped at 4 pi?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test case that earthArea is 4*Pi steradians. I don't think a check in the function is necessary; it's implicit from the equation of a sphere's area.

steradians float64
area unit.Area
}{
{1, earthArea / 4 / math.Pi},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you want to pull this repeated set out like degreesToMeters mapping that is used to test both directions of conversion?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

s2.LatLngFromDegrees(35.6733227, 139.6403486), s1.Degree * 29.2},
{"Japan to Spain", s2.LatLngFromDegrees(35.6733227, 139.6403486),
s2.LatLngFromDegrees(40.4379332, -3.749576), s1.Degree * -27.2},
} {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// If a == b, a == -b, or a is one of the Earth's poles, the return value is undefined.

Will it crash or just give an indeterminate answer if you added one or two of these cases?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test to ensure it returns a real, but unspecified value. Test comment explains why the value is undefined.

@rsned
Copy link
Collaborator

rsned commented Jun 27, 2025

I suppose we wont be able to update s2/s2_test to use this to get the "const earthRadiusKm = 6371.01" because we'd end up with circular imports.

@jmr jmr changed the title Go implementation of S2Earth, using go-units library Add S2Earth Jun 27, 2025
@flwyd
Copy link
Collaborator Author

flwyd commented Jun 30, 2025

I suppose we wont be able to update s2/s2_test to use this to get the "const earthRadiusKm = 6371.01" because we'd end up with circular imports.

Correct. If we put an Earth type inside the s2 package we'd be able to use it in that way, but that might tempt future authors to depend on Earth measurements from pure S2 types, which we should discourage.

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.

Port S2Earth
3 participants