Browse Source

first

master
simon 4 months ago
commit
47c2e90b78
  1. 70
      assets/borders/Readme.txt
  2. BIN
      assets/borders/TM_WORLD_BORDERS-0.3.dbf
  3. 1
      assets/borders/TM_WORLD_BORDERS-0.3.prj
  4. BIN
      assets/borders/TM_WORLD_BORDERS-0.3.shp
  5. BIN
      assets/borders/TM_WORLD_BORDERS-0.3.shx
  6. BIN
      assets/borders/TM_WORLD_BORDERS-0.3.zip
  7. 962
      assets/countrycode-latlong-array.json
  8. 9322
      assets/dxcc.json
  9. 1
      countries
  10. 76
      hammer.py
  11. 38
      maidenhead/__init__.py
  12. 60
      maidenhead/__main__.py
  13. 19
      maidenhead/tests/conftest.py
  14. 26
      maidenhead/tests/test_all.py
  15. 19
      maidenhead/tests/test_cli.py
  16. 14
      maidenhead/tests/test_maps.py
  17. 65
      maidenhead/to_location.py
  18. 45
      maidenhead/to_maiden.py
  19. 23
      map.txt
  20. 68
      pyWorldMap.py
  21. 27
      test2.py

70
assets/borders/Readme.txt

@ -0,0 +1,70 @@
TM_WORLD_BORDERS-0.1.ZIP
Provided by Bjorn Sandvik, thematicmapping.org
Use this dataset with care, as several of the borders are disputed.
The original shapefile (world_borders.zip, 3.2 MB) was downloaded from the Mapping Hacks website:
http://www.mappinghacks.com/data/
The dataset was derived by Schuyler Erle from public domain sources.
Sean Gilles did some clean up and made some enhancements.
COLUMN TYPE DESCRIPTION
Shape Polygon Country/area border as polygon(s)
FIPS String(2) FIPS 10-4 Country Code
ISO2 String(2) ISO 3166-1 Alpha-2 Country Code
ISO3 String(3) ISO 3166-1 Alpha-3 Country Code
UN Short Integer(3) ISO 3166-1 Numeric-3 Country Code
NAME String(50) Name of country/area
AREA Long Integer(7) Land area, FAO Statistics (2002)
POP2005 Double(10,0) Population, World Polulation Prospects (2005)
REGION Short Integer(3) Macro geographical (continental region), UN Statistics
SUBREGION Short Integer(3) Geogrpahical sub-region, UN Statistics
LON FLOAT (7,3) Longitude
LAT FLOAT (6,3) Latitude
CHANGELOG VERSION 0.3 - 30 July 2008
- Corrected spelling mistake (United Arab Emirates)
- Corrected population number for Japan
- Adjusted long/lat values for India, Italy and United Kingdom
CHANGELOG VERSION 0.2 - 1 April 2008
- Made new ZIP archieves. No change in dataset.
CHANGELOG VERSION 0.1 - 13 March 2008
- Polygons representing each country were merged into one feature
- Åland Islands was extracted from Finland
- Hong Kong was extracted from China
- Holy See (Vatican City) was added
- Gaza Strip and West Bank was merged into "Occupied Palestinean Territory"
- Saint-Barthelemy was extracted from Netherlands Antilles
- Saint-Martin (Frensh part) was extracted from Guadeloupe
- Svalbard and Jan Mayen was merged into "Svalbard and Jan Mayen Islands"
- Timor-Leste was extracted from Indonesia
- Juan De Nova Island was merged with "French Southern & Antarctic Land"
- Baker Island, Howland Island, Jarvis Island, Johnston Atoll, Midway Islands
and Wake Island was merged into "United States Minor Outlying Islands"
- Glorioso Islands, Parcel Islands, Spartly Islands was removed
(almost uninhabited and missing ISO-3611-1 code)
- Added ISO-3166-1 codes (alpha-2, alpha-3, numeric-3). Source:
https://www.cia.gov/library/publications/the-world-factbook/appendix/appendix-d.html
http://unstats.un.org/unsd/methods/m49/m49alpha.htm
http://www.fysh.org/~katie/development/geography.txt
- AREA column has been replaced with data from UNdata:
Land area, 1000 hectares, 2002, FAO Statistics
- POPULATION column (POP2005) has been replaced with data from UNdata:
Population, 2005, Medium variant, World Population Prospects: The 2006 Revision
- Added region and sub-region codes from UN Statistics Division. Source:
http://unstats.un.org/unsd/methods/m49/m49regin.htm
- Added LAT, LONG values for each country

BIN
assets/borders/TM_WORLD_BORDERS-0.3.dbf

Binary file not shown.

1
assets/borders/TM_WORLD_BORDERS-0.3.prj

@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]

BIN
assets/borders/TM_WORLD_BORDERS-0.3.shp

Binary file not shown.

BIN
assets/borders/TM_WORLD_BORDERS-0.3.shx

Binary file not shown.

BIN
assets/borders/TM_WORLD_BORDERS-0.3.zip

Binary file not shown.

962
assets/countrycode-latlong-array.json

@ -0,0 +1,962 @@
{
"ad": [
"42.5000",
"1.5000"
],
"ae": [
"24.0000",
"54.0000"
],
"af": [
"33.0000",
"65.0000"
],
"ag": [
"17.0500",
"-61.8000"
],
"ai": [
"18.2500",
"-63.1667"
],
"al": [
"41.0000",
"20.0000"
],
"am": [
"40.0000",
"45.0000"
],
"an": [
"12.2500",
"-68.7500"
],
"ao": [
"-12.5000",
"18.5000"
],
"ap": [
"35.0000",
"105.0000"
],
"aq": [
"-90.0000",
"0.0000"
],
"ar": [
"-34.0000",
"-64.0000"
],
"as": [
"-14.3333",
"-170.0000"
],
"at": [
"47.3333",
"13.3333"
],
"au": [
"-27.0000",
"133.0000"
],
"aw": [
"12.5000",
"-69.9667"
],
"az": [
"40.5000",
"47.5000"
],
"ba": [
"44.0000",
"18.0000"
],
"bb": [
"13.1667",
"-59.5333"
],
"bd": [
"24.0000",
"90.0000"
],
"be": [
"50.8333",
"4.0000"
],
"bf": [
"13.0000",
"-2.0000"
],
"bg": [
"43.0000",
"25.0000"
],
"bh": [
"26.0000",
"50.5500"
],
"bi": [
"-3.5000",
"30.0000"
],
"bj": [
"9.5000",
"2.2500"
],
"bm": [
"32.3333",
"-64.7500"
],
"bn": [
"4.5000",
"114.6667"
],
"bo": [
"-17.0000",
"-65.0000"
],
"br": [
"-10.0000",
"-55.0000"
],
"bs": [
"24.2500",
"-76.0000"
],
"bt": [
"27.5000",
"90.5000"
],
"bv": [
"-54.4333",
"3.4000"
],
"bw": [
"-22.0000",
"24.0000"
],
"by": [
"53.0000",
"28.0000"
],
"bz": [
"17.2500",
"-88.7500"
],
"ca": [
"60.0000",
"-95.0000"
],
"cc": [
"-12.5000",
"96.8333"
],
"cd": [
"0.0000",
"25.0000"
],
"cf": [
"7.0000",
"21.0000"
],
"cg": [
"-1.0000",
"15.0000"
],
"ch": [
"47.0000",
"8.0000"
],
"ci": [
"8.0000",
"-5.0000"
],
"ck": [
"-21.2333",
"-159.7667"
],
"cl": [
"-30.0000",
"-71.0000"
],
"cm": [
"6.0000",
"12.0000"
],
"cn": [
"35.0000",
"105.0000"
],
"co": [
"4.0000",
"-72.0000"
],
"cr": [
"10.0000",
"-84.0000"
],
"cu": [
"21.5000",
"-80.0000"
],
"cv": [
"16.0000",
"-24.0000"
],
"cx": [
"-10.5000",
"105.6667"
],
"cy": [
"35.0000",
"33.0000"
],
"cz": [
"49.7500",
"15.5000"
],
"de": [
"51.0000",
"9.0000"
],
"dj": [
"11.5000",
"43.0000"
],
"dk": [
"56.0000",
"10.0000"
],
"dm": [
"15.4167",
"-61.3333"
],
"do": [
"19.0000",
"-70.6667"
],
"dz": [
"28.0000",
"3.0000"
],
"ec": [
"-2.0000",
"-77.5000"
],
"ee": [
"59.0000",
"26.0000"
],
"eg": [
"27.0000",
"30.0000"
],
"eh": [
"24.5000",
"-13.0000"
],
"er": [
"15.0000",
"39.0000"
],
"es": [
"40.0000",
"-4.0000"
],
"et": [
"8.0000",
"38.0000"
],
"eu": [
"47.0000",
"8.0000"
],
"fi": [
"64.0000",
"26.0000"
],
"fj": [
"-18.0000",
"175.0000"
],
"fk": [
"-51.7500",
"-59.0000"
],
"fm": [
"6.9167",
"158.2500"
],
"fo": [
"62.0000",
"-7.0000"
],
"fr": [
"46.0000",
"2.0000"
],
"ga": [
"-1.0000",
"11.7500"
],
"gb": [
"54.0000",
"-2.0000"
],
"gd": [
"12.1167",
"-61.6667"
],
"ge": [
"42.0000",
"43.5000"
],
"gf": [
"4.0000",
"-53.0000"
],
"gh": [
"8.0000",
"-2.0000"
],
"gi": [
"36.1833",
"-5.3667"
],
"gl": [
"72.0000",
"-40.0000"
],
"gm": [
"13.4667",
"-16.5667"
],
"gn": [
"11.0000",
"-10.0000"
],
"gp": [
"16.2500",
"-61.5833"
],
"gq": [
"2.0000",
"10.0000"
],
"gr": [
"39.0000",
"22.0000"
],
"gs": [
"-54.5000",
"-37.0000"
],
"gt": [
"15.5000",
"-90.2500"
],
"gu": [
"13.4667",
"144.7833"
],
"gw": [
"12.0000",
"-15.0000"
],
"gy": [
"5.0000",
"-59.0000"
],
"hk": [
"22.2500",
"114.1667"
],
"hm": [
"-53.1000",
"72.5167"
],
"hn": [
"15.0000",
"-86.5000"
],
"hr": [
"45.1667",
"15.5000"
],
"ht": [
"19.0000",
"-72.4167"
],
"hu": [
"47.0000",
"20.0000"
],
"id": [
"-5.0000",
"120.0000"
],
"ie": [
"53.0000",
"-8.0000"
],
"il": [
"31.5000",
"34.7500"
],
"in": [
"20.0000",
"77.0000"
],
"io": [
"-6.0000",
"71.5000"
],
"iq": [
"33.0000",
"44.0000"
],
"ir": [
"32.0000",
"53.0000"
],
"is": [
"65.0000",
"-18.0000"
],
"it": [
"42.8333",
"12.8333"
],
"jm": [
"18.2500",
"-77.5000"
],
"jo": [
"31.0000",
"36.0000"
],
"jp": [
"36.0000",
"138.0000"
],
"ke": [
"1.0000",
"38.0000"
],
"kg": [
"41.0000",
"75.0000"
],
"kh": [
"13.0000",
"105.0000"
],
"ki": [
"1.4167",
"173.0000"
],
"km": [
"-12.1667",
"44.2500"
],
"kn": [
"17.3333",
"-62.7500"
],
"kp": [
"40.0000",
"127.0000"
],
"kr": [
"37.0000",
"127.5000"
],
"kw": [
"29.3375",
"47.6581"
],
"ky": [
"19.5000",
"-80.5000"
],
"kz": [
"48.0000",
"68.0000"
],
"la": [
"18.0000",
"105.0000"
],
"lb": [
"33.8333",
"35.8333"
],
"lc": [
"13.8833",
"-61.1333"
],
"li": [
"47.1667",
"9.5333"
],
"lk": [
"7.0000",
"81.0000"
],
"lr": [
"6.5000",
"-9.5000"
],
"ls": [
"-29.5000",
"28.5000"
],
"lt": [
"56.0000",
"24.0000"
],
"lu": [
"49.7500",
"6.1667"
],
"lv": [
"57.0000",
"25.0000"
],
"ly": [
"25.0000",
"17.0000"
],
"ma": [
"32.0000",
"-5.0000"
],
"mc": [
"43.7333",
"7.4000"
],
"md": [
"47.0000",
"29.0000"
],
"me": [
"42.0000",
"19.0000"
],
"mg": [
"-20.0000",
"47.0000"
],
"mh": [
"9.0000",
"168.0000"
],
"mk": [
"41.8333",
"22.0000"
],
"ml": [
"17.0000",
"-4.0000"
],
"mm": [
"22.0000",
"98.0000"
],
"mn": [
"46.0000",
"105.0000"
],
"mo": [
"22.1667",
"113.5500"
],
"mp": [
"15.2000",
"145.7500"
],
"mq": [
"14.6667",
"-61.0000"
],
"mr": [
"20.0000",
"-12.0000"
],
"ms": [
"16.7500",
"-62.2000"
],
"mt": [
"35.8333",
"14.5833"
],
"mu": [
"-20.2833",
"57.5500"
],
"mv": [
"3.2500",
"73.0000"
],
"mw": [
"-13.5000",
"34.0000"
],
"mx": [
"23.0000",
"-102.0000"
],
"my": [
"2.5000",
"112.5000"
],
"mz": [
"-18.2500",
"35.0000"
],
"na": [
"-22.0000",
"17.0000"
],
"nc": [
"-21.5000",
"165.5000"
],
"ne": [
"16.0000",
"8.0000"
],
"nf": [
"-29.0333",
"167.9500"
],
"ng": [
"10.0000",
"8.0000"
],
"ni": [
"13.0000",
"-85.0000"
],
"nl": [
"52.5000",
"5.7500"
],
"no": [
"62.0000",
"10.0000"
],
"np": [
"28.0000",
"84.0000"
],
"nr": [
"-0.5333",
"166.9167"
],
"nu": [
"-19.0333",
"-169.8667"
],
"nz": [
"-41.0000",
"174.0000"
],
"om": [
"21.0000",
"57.0000"
],
"pa": [
"9.0000",
"-80.0000"
],
"pe": [
"-10.0000",
"-76.0000"
],
"pf": [
"-15.0000",
"-140.0000"
],
"pg": [
"-6.0000",
"147.0000"
],
"ph": [
"13.0000",
"122.0000"
],
"pk": [
"30.0000",
"70.0000"
],
"pl": [
"52.0000",
"20.0000"
],
"pm": [
"46.8333",
"-56.3333"
],
"pr": [
"18.2500",
"-66.5000"
],
"ps": [
"32.0000",
"35.2500"
],
"pt": [
"39.5000",
"-8.0000"
],
"pw": [
"7.5000",
"134.5000"
],
"py": [
"-23.0000",
"-58.0000"
],
"qa": [
"25.5000",
"51.2500"
],
"re": [
"-21.1000",
"55.6000"
],
"ro": [
"46.0000",
"25.0000"
],
"rs": [
"44.0000",
"21.0000"
],
"ru": [
"60.0000",
"100.0000"
],
"rw": [
"-2.0000",
"30.0000"
],
"sa": [
"25.0000",
"45.0000"
],
"sb": [
"-8.0000",
"159.0000"
],
"sc": [
"-4.5833",
"55.6667"
],
"sd": [
"15.0000",
"30.0000"
],
"se": [
"62.0000",
"15.0000"
],
"sg": [
"1.3667",
"103.8000"
],
"sh": [
"-15.9333",
"-5.7000"
],
"si": [
"46.0000",
"15.0000"
],
"sj": [
"78.0000",
"20.0000"
],
"sk": [
"48.6667",
"19.5000"
],
"sl": [
"8.5000",
"-11.5000"
],
"sm": [
"43.7667",
"12.4167"
],
"sn": [
"14.0000",
"-14.0000"
],
"so": [
"10.0000",
"49.0000"
],
"sr": [
"4.0000",
"-56.0000"
],
"st": [
"1.0000",
"7.0000"
],
"sv": [
"13.8333",
"-88.9167"
],
"sy": [
"35.0000",
"38.0000"
],
"sz": [
"-26.5000",
"31.5000"
],
"tc": [
"21.7500",
"-71.5833"
],
"td": [
"15.0000",
"19.0000"
],
"tf": [
"-43.0000",
"67.0000"
],
"tg": [
"8.0000",
"1.1667"
],
"th": [
"15.0000",
"100.0000"
],
"tj": [
"39.0000",
"71.0000"
],
"tk": [
"-9.0000",
"-172.0000"
],
"tm": [
"40.0000",
"60.0000"
],
"tn": [
"34.0000",
"9.0000"
],
"to": [
"-20.0000",
"-175.0000"
],
"tr": [
"39.0000",
"35.0000"
],
"tt": [
"11.0000",
"-61.0000"
],
"tv": [
"-8.0000",
"178.0000"
],
"tw": [
"23.5000",
"121.0000"
],
"tz": [
"-6.0000",
"35.0000"
],
"ua": [
"49.0000",
"32.0000"
],
"ug": [
"1.0000",
"32.0000"
],
"um": [
"19.2833",
"166.6000"
],
"us": [
"38.0000",
"-97.0000"
],
"uy": [
"-33.0000",
"-56.0000"
],
"uz": [
"41.0000",
"64.0000"
],
"va": [
"41.9000",
"12.4500"
],
"vc": [
"13.2500",
"-61.2000"
],
"ve": [
"8.0000",
"-66.0000"
],
"vg": [
"18.5000",
"-64.5000"
],
"vi": [
"18.3333",
"-64.8333"
],
"vn": [
"16.0000",
"106.0000"
],
"vu": [
"-16.0000",
"167.0000"
],
"wf": [
"-13.3000",
"-176.2000"
],
"ws": [
"-13.5833",
"-172.3333"
],
"ye": [
"15.0000",
"48.0000"
],
"yt": [
"-12.8333",
"45.1667"
],
"za": [
"-29.0000",
"24.0000"
],
"zm": [
"-15.0000",
"30.0000"
],
"zw": [
"-20.0000",
"30.0000"
]
}

9322
assets/dxcc.json

File diff suppressed because it is too large

1
countries

@ -0,0 +1 @@
Subproject commit eedc57f482d9a1911aba84f1d23b7a392af9e8c8

76
hammer.py

@ -0,0 +1,76 @@
import maidenhead
from countries import countries
import json
import re
from math import exp, radians, cos, sin, asin, sqrt
mypos = maidenhead.to_location("JO66OA18")
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return c * r
def main():
output = []
p = []
# Try to parse callsign
with open('assets/countrycode-latlong-array.json') as f:
ccmap = json.load(f)
cc = countries.CountryChecker('assets/borders/TM_WORLD_BORDERS-0.3.shp')
inp = input("INPUT: ")
# Try to parse as maidenhead
try:
x,y = maidenhead.to_location(inp)
c = cc.getCountry(countries.Point(x,y))
output.append("--------------LOCATOR---------------")
output.append("Locator: %s : Country: %s, distance: %s km" % (inp, c, round(haversine(mypos[1], mypos[0], y,x))))
p.append[x,y]
except:
pass
# Try to parse callsign
with open('assets/dxcc.json') as f:
data = json.load(f)
for d in data["dxcc"]:
if not d["prefixRegex"]:
continue
result = re.match(d["prefixRegex"], inp, re.IGNORECASE)
if result:
output.append("--------------CALLSIGN---------------")
output.append("Callsign %s is from %s" % (inp, d["name"]))
try:
p = ccmap[d["countryCode"].lower()]
output.append("Callsign: distance to callsign %s : %s km" % (
inp,
round(haversine(mypos[1], mypos[0], float(p[1]),float(p[0]))))
)
except:
pass
print("\n".join(output))
if __name__ == "__main__":
main()

38
maidenhead/__init__.py

@ -0,0 +1,38 @@
"""
Maidenhead grid conversion <==> latitude, longitude
toMaiden([lat, lon], level) returns a char (len = lvl*2)
toLoc(mloc) takes any string and returns topleft [lat,lon] within mloc
Beyond 8 characters is not defined for Maidenhead.
"""
from .to_location import to_location
from .to_maiden import to_maiden
def google_maps(maiden: str, center: bool = False) -> str:
"""
generate Google Maps URL from Maidenhead grid
Parameters
----------
maiden : str
Maidenhead grid
center : bool
If true, return the center of provided maidenhead grid square, instead of default south-west corner
Results
-------
url : str
Google Maps URL
"""
loc = to_location(maiden, center)
url = f"https://www.google.com/maps/@?api=1&map_action=map&center={loc[0]},{loc[1]}"
return url

60
maidenhead/__main__.py

@ -0,0 +1,60 @@
import argparse
import typing as T
from copy import copy
import maidenhead
def main(
loc: T.Union[str, T.Sequence[float]],
precision: int = 3,
url: bool = False,
center: bool = False,
):
if isinstance(loc, str): # maidenhead
maiden = copy(loc)
loc = maidenhead.to_location(loc, center)
print(f"{loc[0]:.4f} {loc[1]:.4f}")
elif len(loc) == 2: # lat lon
if isinstance(loc[0], str):
loc = list(map(float, loc))
maiden = maidenhead.to_maiden(*loc, precision=precision)
print(maiden)
loc = maiden
else:
raise ValueError("specify Maidenhead grid (single string) or lat lon (with space between)")
if url:
uri = maidenhead.google_maps(maiden, center)
print(uri)
return uri
return loc
def cli():
p = argparse.ArgumentParser(description="convert to / from Maidenhead locator")
p.add_argument(
"loc", help="Maidenhead grid (single string) or lat lon (with space between)", nargs="+"
)
p.add_argument("-p", "--precision", help="maidenhead precision", type=int, default=3)
p.add_argument("-u", "--url", help="also output Google Maps URL", action="store_true")
p.add_argument(
"-c",
"--center",
help="output lat lon of the center of provided maidenhead grid square "
"(default output: lat lon of it's south-west corner)",
action="store_true",
)
args = p.parse_args()
if len(args.loc) == 1:
loc = args.loc[0]
else:
loc = args.loc
main(loc, args.precision, args.url, args.center)
if __name__ == "__main__":
cli()

19
maidenhead/tests/conftest.py

@ -0,0 +1,19 @@
import pytest
mcmurdo = (-77.8419, 166.6863)
washington_monument = (38.8895, -77.0353)
giza_pyramid = (29.9792, 31.1342)
class Loc:
def __init__(self, latlon, maiden):
self.latlon = latlon
self.maiden = maiden
@pytest.fixture(
params=[(mcmurdo, "RB32id27"), (washington_monument, "FM18lv53"), (giza_pyramid, "KL59nx65")]
)
def location(request):
return Loc(*request.param)

26
maidenhead/tests/test_all.py

@ -0,0 +1,26 @@
import pytest
from pytest import approx
import maidenhead
def test_latlon2maiden(location):
m = maidenhead.to_maiden(*location.latlon)
assert m == location.maiden[:6]
def test_maiden2latlon(location):
lat, lon = maidenhead.to_location(location.maiden)
assert lat == approx(location.latlon[0], rel=0.0001)
assert lon == approx(location.latlon[1], rel=0.0001)
@pytest.mark.parametrize("invalid", [None, 1, True, False])
def test_invalid_maiden(invalid):
with pytest.raises(AttributeError):
maidenhead.to_location(maiden=invalid)
def test_invalid_maiden_len():
with pytest.raises(ValueError):
maidenhead.to_location(maiden="GG52qjjjjj")

19
maidenhead/tests/test_cli.py

@ -0,0 +1,19 @@
import pytest
from maidenhead.__main__ import main
def test_convert_maiden_to_loc():
assert main((27, 34)) == "KL77aa"
def test_convert_loc_to_maiden():
assert main("GG52qj") == pytest.approx([-27.6250, -48.6667])
@pytest.mark.parametrize("args_str", ["GG52qj", (-27.625, -48.66666666)])
def test_render_maps_url(args_str):
assert (
main(args_str, url=True)
== "https://www.google.com/maps/@?api=1&map_action=map&center=-27.625,-48.666666666666664"
)

14
maidenhead/tests/test_maps.py

@ -0,0 +1,14 @@
import maidenhead as mh
def test_googlemaps_precision(location):
m = mh.to_maiden(*location.latlon, precision=4)
assert m == location.maiden
g4 = mh.google_maps(m)
m1 = mh.to_maiden(*location.latlon)
assert m1 == location.maiden[:6]
g1 = mh.google_maps(m1)
assert g4 != g1

65
maidenhead/to_location.py

@ -0,0 +1,65 @@
import typing as T
def to_location(maiden: str, center: bool = False) -> T.Tuple[float, float]:
"""
convert Maidenhead grid to latitude, longitude
Parameters
----------
maiden : str
Maidenhead grid locator of length 2 to 8
center : bool
If true, return the center of provided maidenhead grid square, instead of default south-west corner
Default value = False needed to maidenhead full backward compatibility of this module.
Returns
-------
latLon : tuple of float
Geographic latitude, longitude
"""
maiden = maiden.strip().upper()
N = len(maiden)
if not 8 >= N >= 2 and N % 2 == 0:
raise ValueError("Maidenhead locator requires 2-8 characters, even number of characters")
Oa = ord("A")
lon = -180.0
lat = -90.0
# %% first pair
lon += (ord(maiden[0]) - Oa) * 20
lat += (ord(maiden[1]) - Oa) * 10
# %% second pair
if N >= 4:
lon += int(maiden[2]) * 2
lat += int(maiden[3]) * 1
# %%
if N >= 6:
lon += (ord(maiden[4]) - Oa) * 5.0 / 60
lat += (ord(maiden[5]) - Oa) * 2.5 / 60
# %%
if N >= 8:
lon += int(maiden[6]) * 5.0 / 600
lat += int(maiden[7]) * 2.5 / 600
# %% move lat lon to the center (if requested)
if center:
if N == 2:
lon += 20 / 2
lat += 10 / 2
elif N == 4:
lon += 2 / 2
lat += 1.0 / 2
elif N == 6:
lon += 5.0 / 60 / 2
lat += 2.5 / 60 / 2
elif N >= 8:
lon += 5.0 / 600 / 2
lat += 2.5 / 600 / 2
return lat, lon

45
maidenhead/to_maiden.py

@ -0,0 +1,45 @@
def to_maiden(lat: float, lon: float = None, *, precision: int = 3) -> str:
"""
Returns a maidenhead string for latitude, longitude at specified level.
Parameters
----------
lat : float or tuple of float
latitude or tuple of latitude, longitude
lon : float, optional
longitude (if not given tuple)
precision : int, optional
level of precision (length of maidenhead grid string output)
Returns
-------
maiden : str
Maidenhead grid string of specified precision
"""
A = ord("A")
a = divmod(lon + 180, 20)
b = divmod(lat + 90, 10)
maiden = chr(A + int(a[0])) + chr(A + int(b[0]))
lon = a[1] / 2.0
lat = b[1]
i = 1
while i < precision:
i += 1
a = divmod(lon, 1)
b = divmod(lat, 1)
if not (i % 2):
maiden += str(int(a[0])) + str(int(b[0]))
lon = 24 * a[1]
lat = 24 * b[1]
else:
maiden += chr(A + int(a[0])) + chr(A + int(b[0]))
lon = 10 * a[1]
lat = 10 * b[1]
if len(maiden) >= 6:
maiden = maiden[:4] + maiden[4:6].lower() + maiden[6:]
return maiden

23
map.txt

@ -0,0 +1,23 @@
. _..::__: ,-"-"._ |] , _,.__
_.___ _ _<_>`!(._`.`-. / _._ `_ ,_/ ' '-._.---.-.__
.{ " " `-==,',._\{ \ / {) / _ ">_,-' ` /-/_
\_.:--. `._ )`^-. "' , [_/( __,/-'
'"' \ " _L |-_,--' ) /. (|
| ,' _)_.\\._<> {} _,' / '
`. / [_/_'` `"( <'} )
\\ .-. ) / `-'"..' `:._ _) '
` \ ( `( / `:\ > \ ,-^. /' '
`._, "" | \`' \| ?_) {\
`=.---. `._._ ,' "` |' ,- '.
| `-._ | / `:`<_|=--._
( > . | , `=.__.`-'\
`. / | |{| ,-.,\ .
| ,' \ / `' ," \
| / |_' | __ /
| | '-' `-' \.
|/ " /
\. '
,/ ______._.--._ _..---.---------.
__,-----"-..?----_/ )\ . ,-'" " (__--/
/__/\/

68
pyWorldMap.py

@ -0,0 +1,68 @@
import pyproj
def inverse_num_in_range(num, minNum, maxNum):
"""
Returns the inverse of a number in a range eg:
reverseNumRange(1, 0, 10) => 9
"""
return (maxNum + minNum) - num
def get_map_string():
"""
Loads the map from the txt file and returns the string with newLines
"""
f = open("map.txt")
map = []
for l in f.readlines():
l = l.replace("\n", "")
map.append([char for char in l])
return map
def lat_lon_to_X_Y(lat, lon):
"""
Takes a Lat, Lon pair and return the Mercador projection X, Y suitable for this map
It ignores the very top and bottom of the map due to them being arctic regions and empty
Lat range:
"""
print(lat, lon)
transformer = pyproj.Transformer.from_crs("EPSG:4326", "EPSG:3857")
x, y = transformer.transform(lat, lon)
# we standardise the coords in the given ranges here, so it becomes a percentage
xRange = (-20037508.34, 20037508.34)
yRange = (-20048966.10, 20048966.10)
x_percent = (x - xRange[0]) / (xRange[1] - xRange[0])
y_percent = (y - yRange[0]) / (yRange[1] - yRange[0])
# we then take that percentage and apply it to the map width or height
mapCols = 69
mapRows = 41
mapX = int(x_percent * mapCols)
mapY = int(y_percent * mapRows)
# we have to reverse the y
mapY = inverse_num_in_range(mapY, 0, mapRows)
# ANything above or below our
topMargin = 10
bottomMargin = 10
if mapY - topMargin < 0 or mapY > mapRows-bottomMargin:
raise ValueError('The Lat, Lon ({}, {}) was above or below our margins'.format(lat, lon))
return mapX, mapY - topMargin
# addLog(" ({:.2f} - {:.2f}) / ({:.2f} - {:.2f})".format(x, xRange[0], xRange[1], xRange[0]))
# addLog(" ({:.2f}) / ({:.2f}) = {}".format(x - xRange[0], xRange[1] - xRange[0], x_percent))
# addLog(" ({:.2f} - {:.2f}) / ({:.2f} - {:.2f})".format(y, yRange[0], yRange[1], yRange[0]))
# addLog(" ({:.2f}) / ({:.2f}) = {}".format(y - yRange[0], xRange[1] - yRange[0], y_percent))
# addLog("({:.1f} : {:.1f}) -> ({:.1f}, {:.1f})".format(lon, lat, x, y))
# addLog("{} ({:.2f}, {:.2f}) : ({:.2f} x {}, {:.2f} x {}) -> ({}, {})".format(char, x, y, x_percent, mapRows, y_percent, mapCols, mapX, mapY))
# addLog("")

27
test2.py

@ -0,0 +1,27 @@
import os
import curses
from pyWorldMap import *
def main():
RED = "\033[1;31m"
BLUE = "\033[1;34m"
CYAN = "\033[1;36m"
GREEN = "\033[0;32m"
RESET = "\033[0;0m"
BOLD = "\033[;1m"
REVERSE = "\033[;7m"
worldMap = get_map_string()
x,y = lat_lon_to_X_Y(51.50853, -0.12574)
worldMap[y][x] = RED + "#" + RESET
x,y = lat_lon_to_X_Y(62.1983366, 17.5671981)
worldMap[y][x] = "#"
for l in worldMap:
print("".join(l))
main()
Loading…
Cancel
Save