Skip to content

Use spherical_geometry for accurate positioning #97

@martinjohndyer

Description

@martinjohndyer

The SkyGrid.get_tile(coords) function is very questionable, and often returns the wrong answer.

For instance, with the GOTO-8 grid the position 114.48700 -25.94968 is clearly within T0314, but the basic get_tile function only checks for the nearest centre, meaning it returns the wrong responce:

In [1]: from gototile.grid import SkyGrid
   ...: grid = SkyGrid.from_name('GOTO-8')

In [2]: from astropy.coordinates import SkyCoord
   ...: coords = SkyCoord('114.48700 -25.94968', unit='deg')

In [3]: grid.get_tile(coords)
Out[3]: 'T0272'

In [4]: grid.get_tile(coords, overlap=True)
Out[4]: ['T0314']

loc

Using overlap=True forces a different method, based on a base HealPIX grid to determine which points are within each tiles. That was correct in this instance, but can also fail. For example, if the point was within a pixel that's included in a neighbouring tile due to the inclusive=True in mhealpy's query_polygon. For instance the position 114.0 -26.2 slightly below that target is located in a pixel that's within both tiles. If we had to chose between them we'd still pick the closest centre, which clearly is still wrong.

In [6]: coords = SkyCoord('114 -26.2', unit='deg')

In [7]: grid.get_tile(coords)
Out[7]: 'T0272'

In [8]: grid.get_tile(coords, overlap=True)
Out[8]: ['T0272', 'T0314']

loc2

A far better method would be to use the spherical_geometry package https://github.com/spacetelescope/spherical_geometry, as I already point out in a comment.

goto-tile/gototile/grid.py

Lines 764 to 765 in c8ad3f3

# TODO: spherical_geometry has better functions for things like overlaps, areas and
# finding if a point is within an area

This would be perfectly simple to implement, for instance:

In [10]: from spherical_geometry import polygon, vector

In [11]: for tilename in ['T0314', 'T0272']:
    ...:     vertices = grid.vertices[grid.tilenames.index(tilename)]
    ...:     poly = polygon.SphericalPolygon.from_radec(vertices.ra, vertices.dec)
    ...:     target_vector = vector.radec_to_vector(coords.ra.deg, coords.dec.deg)
    ...:     print(tilename, poly.contains_point(target_vector))
T0314 True
T0272 False

Really the backend of the grid should be rewritten to use that package, with the tile polygons being precalculated with the grid. It would also give us better functions such as getting the area covered by each tile, or a test for overlaps.

Of course, you could still get cases where a point is is multiple tiles. Then if requested with overlap=False (the default) the best would be to return the case where the point was closer to the tile centre, which is what that function was supposed to do.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions