Skip to content
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

WGS84 to Mercator conversion stability #892

Closed
wants to merge 6 commits into from
Closed

Conversation

abyrd
Copy link
Member

@abyrd abyrd commented Oct 16, 2023

As discussed in today's call: Regional request bounds are specified in WGS84 coordinates. Repeating a regional analysis with the same bounds as an existing one involves the UI looking at the web Mercator bounds of an existing analysis and converting them to WGS84 to create the new regional analysis request. This creates a feedback loop between WGS84 and web Mercator where WGS84 bounding boxes lie exactly on the edges of Mercator pixels, creating a literal edge case for the function com.conveyal.r5.analyst.WebMercatorExtents#forWgsEnvelope and populateTask.

I have revised the way web Mercator extents are created to handle the edge case. This is further reinforced with additional factory methods that should handle any numerical instability or lack of precision in the repeated conversions.

The eventual real fix for this is #893.

I also combined all the duplicate methods for WGS84 and Mercator conversions so we don't have two slightly paraphrased copies of each one. The functions were mathematically identical but expressed a little differently which involved some merging, so when reviewing this please help me keep an eye out for any algebraic errors in the math functions or errors in reasoning about use of truncation, ceiling function etc.

I verified repeatedly that the merged functions had the same signatures (parameter and return types), equivalent order of operations etc. but it's always good to have additional pairs of eyes on such things.

Combining these equivalent functions might seem a little off topic for this PR. However, both here and in subsequent work I need to exhaustively check whether we are getting pixel edges or centers. It's harder to be sure you've found all the references in the codebase when the functions to do so are duplicated or wrapped.

Handle edge cases where the WGS84 envelope lies on Mercator pixel edges.
Handle numerical instability in repeated coordinate system conversions.
Add tests for repeated coordinate conversion.
Trimming when handling possibly recycled WGS84 bounds.
Buffering when supplying tight fit opportunity bounding boxes.
WebMercatorGridPointSet methods now call static Grid functions with zoom.
All functions are now using standard Java Math (not FastMath).
Also check stablity of single-pixel extents.
Comment on lines +139 to +141
// Find width and height in whole pixels, handling the case where the right envelope edge is on a pixel edge.
int height = (int) Math.ceil(latToFractionalPixel(wgsEnvelope.getMinY(), zoom) - north);
int width = (int) Math.ceil(lonToFractionalPixel(wgsEnvelope.getMaxX(), zoom) - west);
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that this is a key part of the PR, using ceil() to handle the case where the projected value already lies exactly on a pixel boundary.

@abyrd
Copy link
Member Author

abyrd commented Oct 18, 2023

Coming back to this today: It should be possible to split this into two PRs:

One PR to add the repeated-conversion test and the minimal set of changes to make it pass;

A second PR to merge the WGS84-Mercator conversion functions present on different classes.

The first PR might be easier to review and safer to get into a release without the changes in the second one. And the second one might be better combined with the complete elimination of the wrapper conversion functions as in #894, possibly even creating a third PR to finally switch to the pixel-center functions for destinations.

@abyrd
Copy link
Member Author

abyrd commented Oct 19, 2023

Closing this PR since I've split it into three separate changes. The minimal replacement for this PR is #897.

@abyrd abyrd closed this Oct 19, 2023
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.

1 participant