Geographic Functions: geodesics and rhumblines, orthodromes and loxodromes
Project description
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 of geographiclib.
Compare:
In [1]: from geofun import geodesic_inverse
In [2]: %timeit geodesic_inverse(52, 4, 28, -16.6)
1.17 µs ± 37 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: from geographiclib.geodesic import Geodesic
In [4]: %timeit Geodesic.WGS84.Inverse(52, 4, 28, -16.6)
107 µs ± 170 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
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}
Building
Get poetry if you don’t have it
Check out the source code: git clone https://github.com/jrversteegh/geofun.git --recurse-submodules
Execute poetry build to build the package or poetry install to 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.
Examples
Some 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.
from geofun import Position, Vector
# Just off Hoek van Holland
org = Position(52.0, 4.0)
nm95 = 95 * 1852.0
# Go west 95 nm to Felixstowe
rmbv = Vector(270.0, nm95)
pos1 = org + rmbv
# Go to the same point using great circle line
gcv = pos1 / org
pos2 = org * gcv
# We should end up at the same location
assert pos1 == pos2
# How disappointing: we managed to gain just 9m by crossing the
# North sea using a great circle :p
assert nm95 - gcv.length == 9.101067085022805, f'Unexpected: {gcv.length}'
print(f'From {org} to {pos1}')
print(f'Rhumb: {rmbv}')
print(f'Great circle: {gcv}')
# Another verification
assert pos1 - org == rmbv
assert pos1 / org == gcv
Classes
Position - latitude - longitude
Vector - azimuth - length
Point - x - y
Functions
get_version() -> str
Get the library version
geodesic_direct(latitude: float, longitude: float, azimuth: float, distance: float) -> tuple
Get position and final azimuth after moving distance along great circle with starting azimuth
geodesic_inverse(latitude1: float, longitude1: float, latitude2: float, longitude2: float) -> tuple
Get starting azimuth, distance and ending azimuth of great circle between positions
rhumb_direct(latitude: float, longitude: float, azimuth: float, distance: float) -> tuple
Get position and final azimuth after moving distance from starting position at fixed azimuth/along rhumb line
rhumb_inverse(latitude1: float, longitude1: float, latitude2: float, longitude2: float) -> tuple
Get rhumb line azimuth, distance and final azimuth between positions
angle_diff(arg0: numpy.ndarray[numpy.float64], arg1: numpy.ndarray[numpy.float64]) -> object
Signed difference between to angles
angle_mod(arg0: numpy.ndarray[numpy.float64]) -> object
Return angle bound to [0.0, 360.0>
angle_mod_signed(arg0: numpy.ndarray[numpy.float64]) -> object
Return angle bound to [-180.0, 180.0>
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pygeofun-0.0.6-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ed0a1ade9dff317ee97676d6fe1239238f0a2116701972b5b5023387989b0917 |
|
MD5 | 818cdbdf2e12a23415ce9a767f17ee2f |
|
BLAKE2b-256 | 327df52534917d3721336c8dfcc65ed17132ae4ffccad2337f404c8ce56f5cef |
Hashes for pygeofun-0.0.6-cp310-cp310-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4d71e18a93ad0e9b70524f22c5b24bf8065d9d3e40fad09f0d97a22c9c4fa8c4 |
|
MD5 | 9011ee4d8a081589e87e35538b4a5cf1 |
|
BLAKE2b-256 | 301b6f7d1099d3f3ded54261f2fa6fc527c68e4f393c15a0e772fad5169d7816 |
Hashes for pygeofun-0.0.6-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4d711e5206dbdacfd90814665c51ec0d2ed216f63b2d5c7f193372988a72d43d |
|
MD5 | 79ac6fc15cbee393e3257118dcfa642e |
|
BLAKE2b-256 | 018cb1e1ca12f3194f43c4d363e5757698fa08c62c08e7ef201841f7f7d3c982 |
Hashes for pygeofun-0.0.6-cp39-cp39-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5e5772e537ec23759a7f13a25a97c6f7e482585d8b09a1ccecbc8f6771ba60cb |
|
MD5 | ab507e53676914c6e34d61c8602f2f5e |
|
BLAKE2b-256 | e89a820b3ad194a6aa2024647a74df86b4905ae6e0e5d594958a4a275b225796 |
Hashes for pygeofun-0.0.6-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8c5aa55acf3ea8c82e3800cf0ad8b66dfdd22ca12738b866f517d26c58e6f1fd |
|
MD5 | 93df3b6182bc10601d079f260d10e3b6 |
|
BLAKE2b-256 | 8d663e9bf10b5c76507c7ae03d4d2072911b1661bc5f88961589b817672ed84e |
Hashes for pygeofun-0.0.6-cp38-cp38-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a4e34ea4bb064807043c2a2d52577ca47a1ba9c2fc418d782231c93d73a4c310 |
|
MD5 | c45a3874b10646c64199a8349c129f5d |
|
BLAKE2b-256 | 885a4ef6686d028903bec95b924390623f0aaa1e080c98f617dc03a0ce2035fd |