Added a new Maidenhead class for plotting grid squares on the world map. Work in progress. Addresses issue #59.

pull/65/head
Christian Jacobs 2018-03-08 22:17:16 +00:00
rodzic f222d5cc30
commit 0a4b3da902
1 zmienionych plików z 86 dodań i 0 usunięć

Wyświetl plik

@ -19,6 +19,7 @@
from gi.repository import GObject
import logging
import re
from os.path import expanduser
from datetime import datetime
try:
@ -33,6 +34,7 @@ try:
import cartopy
logging.info("Using version %s of cartopy." % (cartopy.__version__))
from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
from matplotlib.backends.backend_gtk3 import NavigationToolbar2GTK3
have_necessary_modules = True
except ImportError as e:
logging.warning(e)
@ -46,6 +48,10 @@ except ImportError:
have_geocoder = False
class NavigationToolbar(NavigationToolbar2GTK3):
toolitems = [t for t in NavigationToolbar2GTK3.toolitems if t[0] in ("Home", "Zoom", "Save")]
class Point:
""" A point on the grey line map. """
def __init__(self, name, latitude, longitude, style="yo"):
@ -64,6 +70,66 @@ class Point:
return
class Maidenhead:
""" The Maidenhead Locator System. """
def __init__(self):
self.upper = "ABCDEFGHIJKLMNOPQR"
self.lower = "abcdefghijklmnopqrstuvwx"
return
def ll2gs(self, latitude, longitude):
""" Convert latitude-longitude coordinates to a Maidenhead grid square locator.
This is based on the code by Walter Underwood, K6WRU (https://ham.stackexchange.com/questions/221/how-can-one-convert-from-lat-long-to-grid-square).
:arg float latitude: The latitude.
:arg float longitude: The longitude.
:rtype: str
:returns: The Maidenhead grid square locator.
"""
adjusted_latitude = latitude + 90
adjusted_longitude = longitude + 180
field_latitude = self.upper[int(adjusted_latitude/10)]
field_longitude = self.upper[int(adjusted_longitude/20)]
square_latitude = int(adjusted_latitude % 10)
square_longitude = int((adjusted_longitude/2) % 10)
return ("%s"*4) % (field_longitude, field_latitude, square_longitude, square_latitude)
def gs2ll(self, grid_square):
""" Convert a Maidenhead grid square locator to latitude-longitude coordinates.
This is based on the gridSquareToLatLon function in HamGridSquare.js by Paul Brewer, KI6CQ (https://gist.github.com/DrPaulBrewer/4279e9d234a1bd6dd3c0), released under the MIT license.
:arg str grid_square: The Maidenhead grid square locator.
:rtype: tuple
:returns: The latitude-longitude coordinates in a tuple.
"""
m = re.match(r"^[A-X][A-X][0-9][0-9]$", grid_square)
if(m):
gs = m.group(0)
latitude = self.latitude4(gs)+0.5
longitude = self.longitude4(gs)+1.0
else:
m = re.match(r"^[A-X][A-X][0-9][0-9][a-x][a-x]$", grid_square)
if(m):
gs = m.group(0)
latitude = self.latitude4(gs) + (1.0/60.0)*2.5*(ord(gs[5])-ord("a")+0.5)
longitude = self.longitude4(gs) + (1.0/60.0)*5*(ord(gs[4])-ord("a")+0.5)
else:
raise ValueError("Unable to parse grid square string.")
return (latitude, longitude)
def latitude4(self, g):
return 10*(ord(g[1]) - ord("A")) + int(g[3])-90
def longitude4(self, g):
return 20*(ord(g[0]) - ord("A")) + 2*int(g[2])-180
class WorldMap:
""" A tool for visualising the world map. """
@ -83,6 +149,8 @@ class WorldMap:
self.fig = matplotlib.figure.Figure()
self.canvas = FigureCanvas(self.fig) # For embedding in the Gtk application
self.builder.get_object("worldmap").pack_start(self.canvas, True, True, 0)
toolbar = NavigationToolbar(self.canvas, self.application.window)
self.builder.get_object("worldmap").pack_start(toolbar, False, False, 0)
self.refresh_event = GObject.timeout_add(1800000, self.draw) # Re-draw the world map automatically after 30 minutes (if the world map tool is visible).
# Add the QTH coordinates for plotting, if available.
@ -99,6 +167,9 @@ class WorldMap:
except ValueError:
logging.warning("Unable to get the QTH name, latitude and/or longitude. The QTH will not be pinpointed on the world map. Check preferences?")
self.maidenhead = Maidenhead()
self.grid_square_count = numpy.zeros((len(self.maidenhead.upper), len(self.maidenhead.upper)), dtype=bool)
self.builder.get_object("worldmap").show_all()
logging.debug("World map ready!")
@ -212,6 +283,21 @@ class WorldMap:
ax.plot(p.longitude, p.latitude, p.style, transform=cartopy.crs.PlateCarree())
ax.text(p.longitude+0.02*p.longitude, p.latitude+0.02*p.latitude, p.name, color="white", size="small", weight="bold")
# Draw Maidenhead grid squares.
xx = numpy.linspace(-180, 180, len(list(self.maidenhead.upper))+1)
yy = numpy.linspace(-90, 90, len(list(self.maidenhead.upper))+1)
A = self.grid_square_count.copy()
A[10, 10] = True
A[12, 12] = True
A[10, 5] = True
A[9, 5] = True
z = numpy.ma.masked_array(A, A == 0)
ax.pcolormesh(xx, yy, z, transform=cartopy.crs.PlateCarree(), cmap='Purples', vmin=0, vmax=1, edgecolors="k", linewidth=2, alpha=0.6)
for i in range(len(self.maidenhead.upper)):
for j in range(len(self.maidenhead.upper)):
text = self.maidenhead.upper[i]+self.maidenhead.upper[j]
ax.text((xx[i]+xx[i+1])/2.0, (yy[j]+yy[j+1])/2.0, text, ha="center", va="center", size=8, color="w")
return True
else:
return False # Don't try to re-draw the canvas if the necessary modules to do so could not be imported.