
# mercatorTrip.py
# Andrew Davison, ad@coe.psu.ac.th, July 2025
'''
  Draw GreatCircle and Rhumb line between two cities
  on a Mercator map

  Possible cities: = New York  Plymouth  Tokyo Berkeley
         Cape Town  Panama City  Seattle   Melbourne
'''

import cartopy.crs as ccrs
import cartopy.feature as cf
import matplotlib.pyplot as plt
import nav


def plotCity(ax, city, lat, lon):
  # Add marker
  ax.plot(lon, lat, 'o', color='green', 
         transform=ccrs.PlateCarree())
  # label city
  ax.text(lon, lat, " "+city, color='green', 
         transform=ccrs.PlateCarree())



# get coordinates for the cities
startCity = input("Start city? ").title()
endCity = input("End City? ").title()
cities = nav.loadCityData()
lat1, lon1 = nav.readCoord(cities, startCity) 
lat2, lon2 = nav.readCoord(cities, endCity)
print(f"{startCity} (lat,lon): ({lat1:.2f}, {lon1:.2f})")
print(f"{endCity} (lat,lon): ({lat2:.2f}, {lon2:.2f})")


plt.figure(f"{startCity} to {endCity}", figsize=(8,6))


usesDL = nav.usesDateline(lon1, lon2)
if usesDL:
  print("Crosses the dateline")
  proj = ccrs.Mercator(central_longitude=180)
else:
  proj = ccrs.Mercator()

# proj.threshold = proj.threshold/20  # finer threshold
ax = plt.axes(projection=proj)

if usesDL:
  if lon1 < 0:
    lon1 += 360
  else:
    lon2 += 360
  extent = nav.limitExtent(lat1, lon1, lat2, lon2)
else:
  extent = nav.limitExtent(lat1, lon1, lat2, lon2)

ax.set_extent(extent, crs=ccrs.PlateCarree())
ax.gridlines(draw_labels=True)
ax.coastlines()
ax.add_feature(cf.BORDERS, ls=':')


# draw the Great Circle as a series of coordinates
coords = nav.greatCircleCoords(lat1, lon1, lat2, lon2, 20)
print("\nGreat Circle (lat,lon)s and deg Bearing:")
for coord in coords:
  cLat, cLon, cBear = coord
  print(f"  ({cLat:.2f}, {cLon:.2f}); {cBear:.2f}")

lats, lons, _ = zip(*coords)
if usesDL:
  lons = [ lon+360 if lon < 0 else lon for lon in lons]
plt.plot(lons, lats, color='blue', linestyle='--',
         label="Nav Great Circle",
         transform=ccrs.PlateCarree())
                # straight lines coonect coords

# show GC length on the map
dist = nav.distTo(lat1, lon1, lat2, lon2)
print(f"\nGreat Circle distance: {dist:.0f} km")
lat, lon, _ = coords[len(coords)//2]
plt.text(lon, lat, f" {dist:.0f}km",
         color='green', transform=ccrs.PlateCarree())


# ---
# draw the Rhumb line as a series of coordinates
coords = nav.rhumbCoords(lat1, lon1, lat2, lon2, 20)
print("\nRhumb Line (lat,lon)s and deg Bearing:")
for coord in coords:
  cLat, cLon, cBear = coord
  print(f"  ({cLat:.2f}, {cLon:.2f}); {cBear:.2f}")

lats, lons, _ = zip(*coords)
if usesDL:
  lons = [ lon+360 if lon < 0 else lon for lon in lons]
plt.plot(lons, lats, color='red', ls='-.',
    label="Nav Rhumb Line", transform=ccrs.PlateCarree())
                # straight lines connect coords

# show rhumb line length on the map
dist = nav.rhumbDistTo(lat1, lon1, lat2, lon2)
print(f"\nRhumb line distance: {dist:.0f} km")
lat, lon, _ = coords[len(coords)//2]
plt.text(lon, lat, f" {dist:.0f}km",
         color='green', transform=ccrs.PlateCarree())

# label the cities
plotCity(ax, startCity, lat1, lon1)
plotCity(ax, endCity, lat2, lon2)

plt.title(startCity + " to " + endCity)
plt.legend()
plt.show()