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

Increase coords consistency and clamp zoom level to numerically feasible range #273

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

terrorfisch
Copy link

@terrorfisch terrorfisch commented Apr 11, 2023

  • Clamp the integer ZoomLevel to 0..31 when converted from floating point Zoom
  • Restrict traversal of WorldTileCoords to supported zoom level range
  • Construct QuadKey with the morton_encoding crate. This change is here because the previous QuadKey depended on the ZoomLevel type.

Fixes crash from #161 by making the "backend" more robust.

Does not implemented the desired zoom limit. This is done in #180

💻 Examples

You can arbitrarily zoom in/out in the demo without panic.

🚨 Test instructions

Launch demo and start zooming :)

✔️ PR Todo

I am not satisfied with these points yet and lack the domain knowledge to proceed:

  • Check get_children usage in renderer
  • Properly handle signedness of WorldTileCoords
  • Check if saturation in ViewRegion::iter is the correct way to go

Copy link
Collaborator

@maxammann maxammann left a comment

Choose a reason for hiding this comment

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

Still have to go through all, but looks cool!

Did you verify by running this?

key[i + 1] = *part;
pub fn new(zoom_level: ZoomLevel, x: u32, y: u32) -> Self {
// use morton enconding / Z-ordering to build linear quadtree index
let encoded_coords = morton_encoding::morton_encode([x, y]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Interesting approach. As this is used a lot, can we benchmark the encoding/decoding OR do you have a guess on how fast this is?

Copy link
Author

@terrorfisch terrorfisch Apr 12, 2023

Choose a reason for hiding this comment

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

It compiles to ~20 branchless instructions of x86 and should be really fast: https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=6693a9f5ac38027b1fefe470f4208428 (select ASM in the ... menu on the top left)

EDIT: And it should make the comparison operation a lot cheaper.

maplibre/src/coords.rs Show resolved Hide resolved
maplibre/src/coords.rs Outdated Show resolved Hide resolved
@terrorfisch
Copy link
Author

Did you verify by running this?

Yes. Works on my Windows 10 machine.

/// [here](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels).
/// This implementation allows 30 because this covers all tile sizes that can be represented
/// with signed 32-bit integers.
pub(crate) const MAX_ZOOM: u8 = 30;
Copy link
Author

Choose a reason for hiding this comment

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

This should probably be an associated constant of ZoomLevel, i.e. ZoomLevel::MAX.

maxammann
maxammann previously approved these changes Apr 15, 2023
Copy link
Collaborator

@maxammann maxammann left a comment

Choose a reason for hiding this comment

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

Looks good overall! I guess there is no important rationale in these changes. If there is one document WHY those changes are necessary.

Happy to accept this though, as it probably helps you to get into the project!


impl std::ops::Add<u8> for ZoomLevel {
type Output = ZoomLevel;
pub(crate) fn max_tile_coord(&self) -> u32 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pub(crate) fn max_tile_coord(&self) -> u32 {
pub fn max_tile_coord(&self) -> u32 {

Comment on lines 396 to 399
// check for out of bound access
let TileCoords {
x, y, z
} = self.into_tile(TileAddressingScheme::XYZ)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Quadkeys should work on WorldTileCoords. Hardcoding here the addressing scheme seems odd

Copy link
Author

Choose a reason for hiding this comment

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

The only purpose here is to reuse the bound check code. Quite hacky. I will refactor it a bit to make that clear.

maplibre/src/render/tile_view_pattern/mod.rs Show resolved Hide resolved
@maxammann
Copy link
Collaborator

Format can be fixed with just fmt

@nyurik nyurik force-pushed the coord_zoom_overflow branch from f692f04 to 7d69e1c Compare June 1, 2023 13:35
@nyurik
Copy link
Member

nyurik commented Jun 1, 2023

Rebased on main, and cargo fmt-ed it

@maxammann
Copy link
Collaborator

@terrorfisch I updated this to the lastest main. If you want to go over it again, then I can review this one.

Regardin the morton-encoding dependency: I think it would be nice to include the efficiency aspect (compiled down to 20 instructions) in the source code as comment.

@maxammann
Copy link
Collaborator

@terrorfisch Same here, I would still love to merge this :)

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.

3 participants