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

Error in the implementation of tile box boundaries #13

Closed
ysig opened this issue Mar 13, 2023 · 8 comments
Closed

Error in the implementation of tile box boundaries #13

ysig opened this issue Mar 13, 2023 · 8 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@ysig
Copy link

ysig commented Mar 13, 2023

Hi,

thank you for this really useful library.

I noticed an unexpected behavior, when I run:

from pyquadkey2 import quadkey
def in_boundaries(lat, lon, res):
    qk = quadkey.from_geo((lat, lon), res)
    min_lat, min_lon = qk.to_geo(quadkey.TileAnchor.ANCHOR_SW)
    max_lat, max_lon = qk.to_geo(quadkey.TileAnchor.ANCHOR_NE)
    assert min_lat <= lat <= max_lat                   # error

for

in_boundaries(-27.052395, 152.97702, 6)

I get an assertion returns AssertionError is being raised, which is a behavior that clearly shouldn't happen as each point should be included in its associated rectangular box (or I'm missing something).

Thank you,

@ymorin-orange
Copy link

ymorin-orange commented Mar 14, 2023

assert min_lat <= lat <= max_lat

This looks fishy. One of the comparison will return True, and that will be compared
to the last element.

I.e. if you add parentheses, it is the same as (min_lat <= lat) <= max_lat, which
would be evaluated as True <= max_lat, which then can't evaluate to True.

Have you tried printing the three values, and splitting the assert in two?

Forget that, that was a lack of coffee speaking...

@muety
Copy link
Owner

muety commented Apr 3, 2024

Sorry, didn't receive any e-mail notifications on this repo in the past time and thus totally missed all recent issues. Will have a look into this later today!

@muety
Copy link
Owner

muety commented Apr 4, 2024

Looks like we're indeed picking up the wrong tile here. Your code yields quadkey 311213, while testing with jquad returns 311211 (one tile above). Perhaps a floating point precision / rounding issue? Definitely something we'll need to look into! Thanks for bringing this up!

@muety
Copy link
Owner

muety commented Apr 4, 2024

This is what it looks like on the map: blue (1) is your query point, green (2 and 3) are SW and NE reported by pyquadkey2 and red (4 and 5) are SW and NE reported by jquad (which are probably the correct ones).

image

fid,lat,lon,color
1,-27.052395,152.97702,1
2,-31.952162238025,151.875,2
3,-27.059125784374,157.5,2
4,-27.05912578437406,151.875,3
5,-21.94304553343818,157.5,3

@muety
Copy link
Owner

muety commented Apr 4, 2024

Actually, the key returned by pyquadkey2 is correct, at least Microsoft's reference implementation yields the same result:

using Microsoft.MapPoint;

double latitude = -27.052395;
double longitude = 152.97702;
int levelOfDetail = 6;

string quadKey = GetQuadKey(latitude, longitude, levelOfDetail);

Console.WriteLine("QuadKey: " + quadKey);  // returns '311213'

static string GetQuadKey(double latitude, double longitude, int levelOfDetail)
{
    int pixelX, pixelY;
    TileSystem.LatLongToPixelXY(latitude, longitude, levelOfDetail, out pixelX, out pixelY);

    int tileX, tileY;
    TileSystem.PixelXYToTileXY(pixelX, pixelY, out tileX, out tileY);

    return TileSystem.TileXYToQuadKey(tileX, tileY, levelOfDetail);
}

But this would mean both ethlo/jquad and CartoDB/python-quadkey are wrong? 🤔

So, the bug must be somewhere in the tile -> bbox calculation part.

@muety
Copy link
Owner

muety commented Apr 4, 2024

I went through every line of the code, but couldn't find the issue. I honestly have no clue what's wrong here. Would love to get some help on this!

@muety muety added bug Something isn't working help wanted Extra attention is needed labels Apr 4, 2024
@cheginit
Copy link

cheginit commented May 1, 2024

I think the issue is here:

return math.round(lat * 1e12) / 1e12, math.round(lon * 1e12) / 1e12

You can check this out in the code below:

import math

def get_quadkey(lat: float, lng: float, zoom: int)->str:
    x = int((lng + 180) / 360 * (1 << zoom))
    y = int((1 - math.log(math.tan(math.radians(lat)) + 1 / math.cos(math.radians(lat))) / math.pi) / 2 * (1 << zoom))
    quadkey = ''
    for i in range(zoom, 0, -1):
        digit = 0
        mask = 1 << (i - 1)
        if (x & mask) != 0:
            digit += 1
        if (y & mask) != 0:
            digit += 2
        quadkey += str(digit)
    return quadkey

get_quadkey(-27.052395, 152.97702, 6)

If you replace int with round you'll get 311213 instead of 311211. In python, int truncates, but round either rounds up or down.

@muety muety closed this as completed in 58bf13a May 2, 2024
@muety
Copy link
Owner

muety commented May 2, 2024

Thanks a lot for your help on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants