Package: pygeofun
Library for doing geographic calculations like distance, azimuth and
position determination for geodesics and rhumb lines, orthodromes and
loxodromes, respectively.This version makes use of GeographicLib for doing most of the
calculations.This is a C++ package that uses pybind11 to wrap the C++ version of
GeographicLib, which makes it faster (~100x) than the pure python
version ofgeographiclib.Compare:In[1]:fromgeofunimportgeodesic_inverseIn[2]:%timeitgeodesic_inverse(52,4,28,-16.6)1.17µs±37nsperloop(mean±std.dev.of7runs,1000000loopseach)In[3]:fromgeographiclib.geodesicimportGeodesicIn[4]:%timeitGeodesic.WGS84.Inverse(52,4,28,-16.6)107µs±170nsperloop(mean±std.dev.of7runs,10000loopseach)In[5]:geodesic_inverse(52,4,28,-16.6)Out[5]:(-139.28471885516532,3168557.154495447,-152.90624110350674)In[6]:Geodesic.WGS84.Inverse(52,4,28,-16.6)Out[6]:{'lat1':52,'lon1':4.0,'lat2':28,'lon2':-16.6,'a12':28.519118381735783,'s12':3168557.1544954455,'azi1':-139.28471885516532,'azi2':-152.90624110350674}BuildingGetpoetryif you don’t have itCheck out the source code:git clonehttps://github.com/jrversteegh/geofun.git--recurse-submodulesExecutepoetry buildto build the package orpoetry installto get a virtual environment to work in. Both require a working
modern C++ compiler. GCC 9.4 and MSVC 14.3 were tested. Others may
work.ExamplesSome operator abuse was used to mark the difference between geodesic and
mercator based operations.+and-are addition and subtraction
in the mercator projection (loxodromes) and*and/are addition
and subtraction on geodesics (orthodromes). If you object to this,
you’re probably right. Any suggestions for a better way are quite
welcome.fromgeofunimportPosition,Vector# Just off Hoek van Hollandorg=Position(52.0,4.0)nm95=95*1852.0# Go west 95 nm to Felixstowermbv=Vector(270.0,nm95)pos1=org+rmbv# Go to the same point using great circle linegcv=pos1/orgpos2=org*gcv# We should end up at the same locationassertpos1==pos2# How disappointing: we managed to gain just 9m by crossing the# North sea using a great circle :passertnm95-gcv.length==9.101067085022805,f'Unexpected:{gcv.length}'print(f'From{org}to{pos1}')print(f'Rhumb:{rmbv}')print(f'Great circle:{gcv}')# Another verificationassertpos1-org==rmbvassertpos1/org==gcvAnother example: flying from Kennedy Airport to Amsterdam Schiphol Airport and splitting
both a great circle and a rhumbline route into segmentsfromgeofunimportPosition,Vector# Both airportsJFK=Position("40°38′23″N 73°46′44″W")AMS=Position("52°18′00″N 4°45′54″E")# Loxodromic route:loxo=(AMS-JFK).split_loxo(JFK,10)# Print list of positions and flight vectorsprint("\nLoxodrome JFK -> AMS:")forp1,p2inzip(loxo[:-1],loxo[1:]):print(f"Position:{p1}, vector:{p2-p1}")print(f"Destination:{p2}")# Orthodromic route:ortho=(AMS/JFK).split_ortho(JFK,10)# Print list of positions and flight vectorsprint("\nOrthodrome JFK -> AMS:")forp1,p2inzip(ortho[:-1],ortho[1:]):print(f"Position:{p1}, vector:{p2/p1}")print(f"Destination:{p2}")ClassesPositionlatitudelongitudePosition(latitude: int, longitude: int)->PositionPosition in arc seconds.Position(latitude: float, longitude: float)->PositionPosition in arc degrees.VectorazimuthlengthVector(azimuth: float, length: float)->VectorPolar vector in arc degrees and meters.PointxyPoint(x: float, y: float)->PointPoint on locally flat coordinate system, x pointing north, y pointing east.Functionsget_version()->strGet the library versiongeodesic_direct(latitude: float, longitude: float, azimuth: float, distance: float)->tupleGet position and final azimuth after moving distance along great circle
with starting azimuthgeodesic_inverse(latitude1: float, longitude1: float, latitude2: float, longitude2: float)->tupleGet starting azimuth, distance and ending azimuth of great circle
between positionsrhumb_direct(latitude: float, longitude: float, azimuth: float, distance: float)->tupleGet position and final azimuth after moving distance from starting
position at fixed azimuth/along rhumb linerhumb_inverse(latitude1: float, longitude1: float, latitude2: float, longitude2: float)->tupleGet rhumb line azimuth, distance and final azimuth between positionsangle_diff(arg0: numpy.ndarray[numpy.float64], arg1: numpy.ndarray[numpy.float64])->objectSigned difference between to anglesangle_mod(arg0: numpy.ndarray[numpy.float64])->objectReturn angle bound to [0.0, 360.0>angle_mod_signed(arg0: numpy.ndarray[numpy.float64])->objectReturn angle bound to [-180.0, 180.0>