convert GridCog to use gridtools (#326)

* deprecated ?ungrid
* added more help text to commands
* separated distance into its own command

fixes #306
This commit is contained in:
classabbyamp 2020-12-22 20:40:24 -05:00 committed by GitHub
parent 39531fd2b0
commit a93aafaa96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 112 deletions

View File

@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Changed ### Changed
- New colour theme for `?greyline`. - New colour theme for `?greyline`.
- Moved great circle distance and bearing calculation from `?ungrid` to `?griddistance`.
- `?ungrid` to `?latlong`.
### Deprecated
- `?ungrid`.
## [2.5.1] - 2020-12-10 ## [2.5.1] - 2020-12-10

View File

@ -8,7 +8,7 @@ the GNU General Public License, version 2.
""" """
import math import gridtools
import discord.ext.commands as commands import discord.ext.commands as commands
@ -20,124 +20,49 @@ class GridCog(commands.Cog):
self.bot = bot self.bot = bot
@commands.command(name="grid", category=cmn.cat.maps) @commands.command(name="grid", category=cmn.cat.maps)
async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str): async def _grid_sq_lookup(self, ctx: commands.Context, lat: float, lon: float):
("""Calculates the grid square for latitude and longitude coordinates, """ ("""Calculates the grid square for latitude and longitude coordinates."""
"""with negative being latitude South and longitude West.""") """\n\nCoordinates should be in decimal format, with negative being latitude South and longitude West."""
grid = "**" """\n\nTo calculate the latitude and longitude from a grid locator, use `latlong`""")
latf = float(lat) + 90 latlong = gridtools.LatLong(lat, lon)
lonf = float(lon) + 180 grid = gridtools.Grid(latlong)
if 0 <= latf <= 180 and 0 <= lonf <= 360:
grid += chr(ord("A") + int(lonf / 20))
grid += chr(ord("A") + int(latf / 10))
grid += chr(ord("0") + int((lonf % 20)/2))
grid += chr(ord("0") + int((latf % 10)/1))
grid += chr(ord("a") + int((lonf - (int(lonf/2)*2)) / (5/60)))
grid += chr(ord("a") + int((latf - (int(latf/1)*1)) / (2.5/60)))
grid += "**"
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f"Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}" embed.title = f"Maidenhead Grid Locator for {latlong.lat:.5f}, {latlong.long:.5f}"
embed.description = grid embed.description = f"**{grid}**"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
else:
embed = cmn.embed_factory(ctx)
embed.title = f"Error generating grid square for {lat}, {lon}."
embed.description = """Coordinates out of range.
The valid ranges are:
- Latitude: `-90` to `+90`
- Longitude: `-180` to `+180`"""
embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="ungrid", aliases=["loc"], category=cmn.cat.maps) @commands.command(name="latlong", aliases=["latlon", "loc", "ungrid"], category=cmn.cat.maps)
async def _location_lookup(self, ctx: commands.Context, grid: str, grid2: str = None): async def _location_lookup(self, ctx: commands.Context, grid: str):
"""Calculates the latitude and longitude for the center of a grid square. ("""Calculates the latitude and longitude for the center of a grid locator."""
If two grid squares are given, the distance and azimuth between them is calculated.""" """\n\nTo calculate the grid locator from a latitude and longitude, use `grid`"""
if grid2 is None or grid2 == "": """\n\n*Warning: `ungrid` will be removed soon. Use one of the other names for this command.*""")
try: grid_obj = gridtools.Grid(grid)
grid = grid.upper()
loc = get_coords(grid)
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f"Latitude and Longitude for {grid}" embed.title = f"Latitude and Longitude for {grid_obj}"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
embed.description = f"**{grid_obj.lat:.5f}, {grid_obj.long:.5f}**"
if len(grid) >= 6: if ctx.invoked_with == "ungrid":
embed.description = f"**{loc[0]:.5f}, {loc[1]:.5f}**" embed.add_field(name="Warning", value=(f"*`{ctx.prefix}ungrid` will be removed soon, use `{ctx.prefix}help "
embed.url = f"https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}" "latlong` to see other names for this command.*"))
else:
embed.description = f"**{loc[0]:.1f}, {loc[1]:.1f}**"
embed.url = f"https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}"
except Exception as e:
embed = cmn.embed_factory(ctx)
embed.title = f"Error generating latitude and longitude for grid {grid}."
embed.description = str(e)
embed.colour = cmn.colours.bad
else:
radius = 6371
try:
grid = grid.upper()
grid2 = grid2.upper()
loc = get_coords(grid)
loc2 = get_coords(grid2)
# Haversine formula
d_lat = math.radians(loc2[0] - loc[0])
d_lon = math.radians(loc2[1] - loc[1])
a = (math.sin(d_lat/2) ** 2
+ math.cos(math.radians(loc[0]))
* math.cos(math.radians(loc2[0]))
* math.sin(d_lon/2) ** 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
d_mi = 0.6213712 * d
# Bearing
y_dist = math.sin(math.radians(loc2[1]-loc[1])) * math.cos(math.radians(loc2[0]))
x_dist = (math.cos(math.radians(loc[0]))
* math.sin(math.radians(loc2[0]))
- math.sin(math.radians(loc[0]))
* math.cos(math.radians(loc2[0]))
* math.cos(math.radians(loc2[1] - loc[1])))
bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360
embed = cmn.embed_factory(ctx)
embed.title = f"Great Circle Distance and Bearing from {grid} to {grid2}"
embed.description = f"**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°"
embed.colour = cmn.colours.good
except Exception as e:
embed = cmn.embed_factory(ctx)
embed.title = f"Error generating great circle distance and bearing from {grid} and {grid2}."
embed.description = str(e)
embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="griddistance", aliases=["griddist", "distance", "dist"], category=cmn.cat.maps)
async def _dist_lookup(self, ctx: commands.Context, grid1: str, grid2: str):
"""Calculates the great circle distance and azimuthal bearing between two grid locators."""
g1 = gridtools.Grid(grid1)
g2 = gridtools.Grid(grid2)
def get_coords(grid: str): dist, bearing = gridtools.grid_distance(g1, g2)
if len(grid) < 3: dist_mi = 0.6214 * dist
raise ValueError("The grid locator must be at least 4 characters long.")
if not grid[0:2].isalpha() or not grid[2:4].isdigit(): embed = cmn.embed_factory(ctx)
if len(grid) <= 4: embed.title = f"Great Circle Distance and Bearing from {g1} to {g2}"
raise ValueError("The grid locator must be of the form AA##.") embed.description = f"**Distance:** {dist:.1f} km ({dist_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°"
if len(grid) >= 6 and not grid[5:7].isalpha(): embed.colour = cmn.colours.good
raise ValueError("The grid locator must be of the form AA##AA.") await ctx.send(embed=embed)
lon = ((ord(grid[0]) - ord("A")) * 20) - 180
lat = ((ord(grid[1]) - ord("A")) * 10) - 90
lon += ((ord(grid[2]) - ord("0")) * 2)
lat += ((ord(grid[3]) - ord("0")) * 1)
if len(grid) >= 6:
# have subsquares
lon += ((ord(grid[4])) - ord("A")) * (5/60)
lat += ((ord(grid[5])) - ord("A")) * (2.5/60)
# move to center of subsquare
lon += (2.5/60)
lat += (1.25/60)
return (lat, lon)
# move to center of square
lon += 1
lat += 0.5
return (lat, lon)
def setup(bot: commands.Bot): def setup(bot: commands.Bot):

View File

@ -1,5 +1,6 @@
discord.py~=1.5.0 discord.py~=1.5.0
ctyparser~=2.0 ctyparser~=2.0
gridtools~=1.0
beautifulsoup4 beautifulsoup4
lxml lxml
pytz pytz