3 Commits

Author SHA1 Message Date
Ian Renton
e6c9bb1853 Extra protection against string lat/longs creeping into the system 2026-02-14 07:57:36 +00:00
Ian Renton
6e7ffd626e Fix CQ/ITU lookups for zones that cross the antemeridian 2026-02-14 07:47:02 +00:00
Ian Renton
4c22861666 Fix CQ/ITU lookups for zones that cross the antemeridian 2026-02-14 07:46:16 +00:00
3 changed files with 30 additions and 7 deletions

View File

@@ -4,6 +4,7 @@ from math import floor
import geopandas import geopandas
from pyproj import Transformer from pyproj import Transformer
from shapely import prepare
from shapely.geometry import Point, Polygon from shapely.geometry import Point, Polygon
TRANSFORMER_OS_GRID_TO_WGS84 = Transformer.from_crs("EPSG:27700", "EPSG:4326") TRANSFORMER_OS_GRID_TO_WGS84 = Transformer.from_crs("EPSG:27700", "EPSG:4326")
@@ -12,25 +13,48 @@ TRANSFORMER_CI_UTM_GRID_TO_WGS84 = Transformer.from_crs("+proj=utm +zone=30 +ell
cq_zone_data = geopandas.GeoDataFrame.from_features(geopandas.read_file("datafiles/cqzones.geojson")) cq_zone_data = geopandas.GeoDataFrame.from_features(geopandas.read_file("datafiles/cqzones.geojson"))
itu_zone_data = geopandas.GeoDataFrame.from_features(geopandas.read_file("datafiles/ituzones.geojson")) itu_zone_data = geopandas.GeoDataFrame.from_features(geopandas.read_file("datafiles/ituzones.geojson"))
for idx in cq_zone_data.index:
prepare(cq_zone_data.at[idx, 'geometry'])
for idx in itu_zone_data.index:
prepare(itu_zone_data.at[idx, 'geometry'])
# Finds out which CQ zone a lat/lon point is in. # Finds out which CQ zone a lat/lon point is in.
def lat_lon_to_cq_zone(lat, lon): def lat_lon_to_cq_zone(lat, lon):
lon = ((lon + 180) % 360) - 180
for index, row in cq_zone_data.iterrows(): for index, row in cq_zone_data.iterrows():
polygon = Polygon(row["geometry"]) polygon = Polygon(row["geometry"])
test_point = Point(lon, lat) test_point = Point(lon, lat)
if polygon.contains(test_point): if polygon.contains(test_point):
return int(row["name"]) return int(row["name"])
# Might have problems around the antemeridian, so if we didn't find a match, try offsetting the point by + or -
# 360 degrees longitude to try the other side of the Earth
if lon < 0:
test_point = Point(lon + 360, lat)
else:
test_point = Point(lon - 360, lat)
if polygon.contains(test_point):
return int(row["name"])
return None return None
# Finds out which ITU zone a lat/lon point is in. # Finds out which ITU zone a lat/lon point is in.
def lat_lon_to_itu_zone(lat, lon): def lat_lon_to_itu_zone(lat, lon):
lon = ((lon + 180) % 360) - 180
for index, row in itu_zone_data.iterrows(): for index, row in itu_zone_data.iterrows():
polygon = Polygon(row["geometry"]) polygon = Polygon(row["geometry"])
test_point = Point(lon, lat) test_point = Point(lon, lat)
if polygon.contains(test_point): if polygon.contains(test_point):
return int(row["name"]) return int(row["name"])
# Might have problems around the antemeridian, so if we didn't find a match, try offsetting the point by + or -
# 360 degrees longitude to try the other side of the Earth
if lon < 0:
test_point = Point(lon + 360, lat)
else:
test_point = Point(lon - 360, lat)
if polygon.contains(test_point):
return int(row["name"])
return None return None

View File

@@ -364,10 +364,10 @@ class LookupHelper:
def infer_latlon_from_callsign_online_lookup(self, call): def infer_latlon_from_callsign_online_lookup(self, call):
data = self.get_qrz_data_for_callsign(call) data = self.get_qrz_data_for_callsign(call)
if data and "latitude" in data and "longitude" in data and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(data["latitude"]) < 89.9: if data and "latitude" in data and "longitude" in data and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(data["latitude"]) < 89.9:
return [data["latitude"], data["longitude"]] return [float(data["latitude"]), float(data["longitude"])]
data = self.get_hamqth_data_for_callsign(call) data = self.get_hamqth_data_for_callsign(call)
if data and "latitude" in data and "longitude" in data and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(data["latitude"]) < 89.9: if data and "latitude" in data and "longitude" in data and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(data["latitude"]) < 89.9:
return [data["latitude"], data["longitude"]] return [float(data["latitude"]), float(data["longitude"])]
else: else:
return None return None
@@ -399,7 +399,7 @@ class LookupHelper:
try: try:
data = self.CALL_INFO_BASIC.get_lat_long(call) data = self.CALL_INFO_BASIC.get_lat_long(call)
if data and "latitude" in data and "longitude" in data: if data and "latitude" in data and "longitude" in data:
loc = [data["latitude"], data["longitude"]] loc = [float(data["latitude"]), float(data["longitude"])]
else: else:
loc = None loc = None
except KeyError: except KeyError:
@@ -408,11 +408,11 @@ class LookupHelper:
if not loc: if not loc:
data = self.get_clublog_xml_data_for_callsign(call) data = self.get_clublog_xml_data_for_callsign(call)
if data and "Lat" in data and "Lon" in data: if data and "Lat" in data and "Lon" in data:
loc = [data["Lat"], data["Lon"]] loc = [float(data["Lat"]), float(data["Lon"])]
if not loc: if not loc:
data = self.get_clublog_api_data_for_callsign(call) data = self.get_clublog_api_data_for_callsign(call)
if data and "Lat" in data and "Lon" in data: if data and "Lat" in data and "Lon" in data:
loc = [data["Lat"], data["Lon"]] loc = [float(data["Lat"]), float(data["Lon"])]
return loc return loc
# Infer a grid locator from a callsign (using DXCC, probably very inaccurate) # Infer a grid locator from a callsign (using DXCC, probably very inaccurate)

View File

@@ -282,7 +282,6 @@ class Spot:
# DX Grid to lat/lon and vice versa in case one is missing # DX Grid to lat/lon and vice versa in case one is missing
if self.dx_grid and not self.dx_latitude: if self.dx_grid and not self.dx_latitude:
try: try:
print(json.dumps(self))
ll = locator_to_latlong(self.dx_grid) ll = locator_to_latlong(self.dx_grid)
self.dx_latitude = ll[0] self.dx_latitude = ll[0]
self.dx_longitude = ll[1] self.dx_longitude = ll[1]