Search code examples
pythongeolocation

s2sphere Cell ID to Corner Vertices


I've got a list of S2 Level 17 Cell ID's from OSMCoverer in the format 487a73cc7c and I need to get the corner points of each one. I've found a script by a user on Reddit here using the Python s2sphere library which I believe I can use but it doesn't output the correct co-ords, they should around 52.80xxxx,-2.xxxxx range.

I think it's something to do with the shift operation on line 5 but I don't know enough to correct it.

import s2sphere
from s2sphere import CellId, LatLng, Cell

def get_corners(s2CellId_str, level):
    c1 = Cell(CellId(int(s2CellId_str,16)<<(60 - 2*level)))

    print(c1)

    c0 = LatLng.from_point(c1.get_center())  # center lat/lon of s2 cell
    v0 = LatLng.from_point(c1.get_vertex(0)) # lat/lon of upper/left corner
    v1 = LatLng.from_point(c1.get_vertex(1)) # lat/lon of lower/left corner
    v2 = LatLng.from_point(c1.get_vertex(2)) # lat/lon of lower/right corner
    v3 = LatLng.from_point(c1.get_vertex(3)) # lat/lon of upper/right corner
    print('    // s2 level ' + str(level) + ' cell id = ' + s2CellId_str)
    print('Center  = ' + str(c0))
    print('Vertex0 = ' + str(v0))
    print('Vertex1 = ' + str(v1))
    print('Vertex2 = ' + str(v2))
    print('Vertex3 = ' + str(v3))

get_corners("487a73cc7c", 17)

Thanks in advance.


Solution

  • Thanks to a helpful user on Reddit who pointed out what I had wasn't considered a CellID but what's referred to as a token, this has been solved.

    CellID has a from_token function that can be used as such.

    import s2sphere
    from s2sphere import CellId, LatLng, Cell
    
    def get_corners(s2CellId_str, level):
        c1 = Cell(CellId.from_token(s2CellId_str))
    
        print(c1)
    
        c0 = LatLng.from_point(c1.get_center())  # center lat/lon of s2 cell
        v0 = LatLng.from_point(c1.get_vertex(0)) # lat/lon of upper/left corner
        v1 = LatLng.from_point(c1.get_vertex(1)) # lat/lon of lower/left corner
        v2 = LatLng.from_point(c1.get_vertex(2)) # lat/lon of lower/right corner
        v3 = LatLng.from_point(c1.get_vertex(3)) # lat/lon of upper/right corner
        print('    // s2 level ' + str(level) + ' cell id = ' + s2CellId_str)
        print('Center  = ' + str(c0))
        print('Vertex0 = ' + str(v0))
        print('Vertex1 = ' + str(v1))
        print('Vertex2 = ' + str(v2))
        print('Vertex3 = ' + str(v3))
    
    get_corners("487a73cc7c", 17)
    

    Documentation: http://s2sphere.readthedocs.io/en/latest/api.html#s2sphere.CellId.from_token

    As a slightly different solution, if you've got the lat/long values, you can do it like this:

    import s2sphere
    lat = 52.809766
    lng = -2.088996
    cell_id = s2sphere.CellId.from_lat_lng(s2sphere.LatLng.from_degrees(lat,lng)).parent(12)
    print (s2sphere.LatLng.from_point(s2sphere.Cell(cell_id).get_center()))
    print (s2sphere.LatLng.from_point(s2sphere.Cell(cell_id).get_vertex(0)))
    print (s2sphere.LatLng.from_point(s2sphere.Cell(cell_id).get_vertex(1)))
    print (s2sphere.LatLng.from_point(s2sphere.Cell(cell_id).get_vertex(2)))
    print (s2sphere.LatLng.from_point(s2sphere.Cell(cell_id).get_vertex(3)))