geodesyc.py

Created by steveg1cmz

Created on August 09, 2023

3.18 KB

Geodesy(Circular): Geodesy (circular) algorithms. Caution: This implement is largely untested. Tested on: Numworks 19.4.0 Numworks 20.3.2


"""Geodesyc: Geodesy (Circular) API.

Note: Circular/Spherical calculations here.
Ellipsoidal calculations can offer better accuracy (0.5% for Earth) (cf. Geodesy).

Bearings are true N (not magnetic), clockwise.
LatLongs are decimal (-ve S or W).

Hint: on Earth, inputs of
4 decimals = 10 m nominal
5 decimals = 1 m

Disclaimer: This implement is mainly untested.

Refs
https://www.movable-type.co.uk/scripts/latlong.html
"""
__version__ = "0.00"

crid="""Geodesy V""" +__version__ +"""
© 2023 SteveG1CMZ"""
movable="""Some algorithms are adapted from https://www.movable-type.co.uk/scripts/latlong.html"""

from math import *

showme = True

todeg=180/pi
torad = pi/180

earthr=6371.000 #circular radius km
kmtoNM=1.852 #nautical miles (exact)

#algorithms

def bearing1(lat1d,lon1d,lat2d,lon2d):
  """Initial bearing.
  Algorithm: from Movable.
  """
  lat1= lat1d*torad
  lat2 = lat2d*torad
  lon1 = lon1d*torad
  lon2 = lon2d*torad
  deltalon=abs(lon2-lon1) #abs?

  y=sin(deltalon)*cos(lat2)
  x= cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(deltalon)
  theta = atan2(y,x)
  bearing= (theta*todeg + 360) % 360
  return bearing #degrees

def bearingback(bear1):
  return (bear1+180) % 360

def greatcircle(lat1d,lon1d,lat2d,lon2d):
  """great circle is Vincenty for great circles.
  Multiply by radius.
  Wiki says it's better conditioned than cos.
  Algorithm: from Wikipedia.
  """
  
  lat1=lat1d*torad
  lat2=lat2d*torad
  lon1=lon1d*torad
  lon2=lon2d*torad

  coslat2=cos(lat2)
  deltalon=abs(lon2-lon1)
  cosdeltalon=cos(deltalon)
  T1=(coslat2*sin(deltalon))**2
  T2=(cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cosdeltalon)**2
  sq=T1+T2
  den=sin(lat1)*sin(lat2) + cos(lat1)*coslat2*cosdeltalon

  delta = atan2(sqrt(sq),den)
  return delta #angular distance(radians, 0-pi)

def gckm(lat1d,lon1d,lat2d,lon2d):
  dist=greatcircle(lat1d,lon1d,lat2d,lon2d)
  return  (dist * earthr)

def pt2(lat1d,lon1d,bearingd,delta):
  """Get pt2 given pt1 bearing and distance.
  delta=(angular) d/R, eg 100 km/earthr km
  Algorithm: from Movable.
  """
  lat1 = lat1d*torad
  lon1 = lon1d*torad
  theta = bearing1*torad

  sinlat1=sin(lat1) #optimisations
  coslat1=cos(lat1)
  sindelta=sin(delta)
  cosdelta=cos(delta)

  lat2 = asin(sinlat1*cosdelta+ coslat1*sindelta*cos(theta))
  lon2 = lon1 + atan2 (sin(theta)*sindelta*coslat1, cosdelta-sinlat1*sin(lat2))

  lat2d=lat2*todeg
  lon2d = lon2*todeg
  lon2d = (lon2 + 540) % 360 - 180 #-180..180
  return (lat2d, lon2d)

def tosexa(degrees):
  mins = degrees-int(degrees)
  mins=60*mins
  secs= (mins-int(mins))
  secs=60*secs

  return (int(degrees),int(mins), secs)

def examples():
  # a few examples
  #London 51.5072° N, 0.1276° W
  #Paris 48.8566 N, 2.3522 E

  km= gckm(51.5072,-0.1276,48.8566,2.3522)
  m= 1000* gckm(51.5072,-0.1276,48.8566,2.3522)
  NM=km/kmtoNM
  print(km,"km")
  print(m,"m")
  print(NM,"NM")
  print(gckm(40,0,60,0))
  print(gckm(0,0,0,40)) 
  
  print(gckm(0,90,0,-90))

  km = gckm(51.5072,-0.1276,51.5072,-0.1276)
  print(km)
  bear1=bearing1(0,0,0,40)
  
  print(bear1,bearingback(bear1),"degrees")
  bear1=bearing1(0,0,90,0)
  print(bear1,bearingback(bear1),"degrees")

if showme or __name__ == "__main__":
  print(crid)
  print(movable)
  examples()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.