I could use some assistance
My final project in a python class is to calculate the distance between 2 lat/long points. My code is really just managing the input & output portions, while using existing code (properly credited) in a function to do the actual calculations.
I've got it working using 1 type of calculation (Haversine), but I want to use a different formula, as they give slightly different results. Having said all that - my problem is - the only source I can find for the calculation I want is written in JavaScript.
Im just starting to wrap my brain around Python & Im not good enough at math to figure out what is calculation and what is JavaScript syntax..

Does anyone know a source for Rhumb Line distance calculation in Python or
Does anyone know a tool that works for doing the translation, or
Can anyone help me with the translation?

Sorry for being so long winded.

Dani AI

Generated

If you are porting the rhumb-line (loxodrome) math from JavaScript, the main gotchas are unit conversion (degrees -> radians), longitude wrap-around at the antimeridian, and handling the dPhi ~= 0 case (near E-W tracks). The canonical spherical formula uses a Mercator latitude difference log(tan(phi/2 + pi/4)); when the numerator and denominator are equal (or nearly so), use cos(phi1) as a stable fallback.

Here is a minimal, self-contained Python version of rhumb-line distance on a sphere (mean Earth radius 6371 km), with the edge cases handled:

from math import radians, tan, pi, log, cos, sqrt

def rhumb_distance(lat1, lon1, lat2, lon2, radius=6371.0):
    phi1, phi2 = radians(lat1), radians(lat2)
    lam1, lam2 = radians(lon1), radians(lon2)

    dphi = phi2 - phi1
    dlam = abs(lam2 - lam1)
    if dlam > pi:  # take shorter E-W path across the antimeridian
        dlam = 2*pi - dlam

    dpsi = log(tan(phi2/2 + pi/4) / tan(phi1/2 + pi/4))
    q = dphi/dpsi if abs(dpsi) > 1e-12 else cos(phi1)

    return radius * sqrt(dphi*dphi + q*q*dlam*dlam)

Notes:

  • Inputs are in degrees; the function converts to radians. See the Python math module for trig/log functions and constants at math.
  • This is a spherical approximation. For WGS84 ellipsoidal accuracy (distance, bearing, and destination) without reimplementing the math, use the maintained Python bindings in geographiclib (Python), which include rhumb-line routines.

Recommended Answers

All 9 Replies

Javascript isn't too hard to understand.
Perhaps you can give us the javascript code.

http://www.movable-type.co.uk/scripts/latlon.js

That is the js?

If you study the .rhumbDistanceTo method, that should give you an idea.
You can use the math module for sin, log, PI, etc

OK there are a couple of different functions I need, so here's the whole thing

# Given a start point and a distance d along constant bearing ?, this will calculate the destination point. If you maintain a constant bearing along a rhumb line, you will gradually spiral in towards one of the poles. 
# Latitude/longitude spherical geodesy formulae & scripts (c) Chris Veness 2002-2010
# http://www.movable-type.co.uk/scripts/latlong.html
Def rhumbLine:
     # Returns the distance from this point to the supplied point, in km, travelling along a rhumb line *
     # see  *
     # input   tLatLon Latitude/longitude of destination point
     # returns Distance in km between this point and destination point

     LatLon.prototype.rhumbDistanceTo = function(point) 
     var R = this._radius
     var lat1 = this._lat.toRad(), lat2 = point._lat.toRad()
     var dLat = (point._lat-this._lat).toRad();
     var dLon = Math.abs(point._lon-this._lon).toRad();
     var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
     var q = (!isNaN(dLat/dPhi)) ? dLat/dPhi : Math.cos(lat1);
     # E-W line gives dPhi=0
     # if dLon over 180° take shorter rhumb across 180° meridian:
     if (dLon > Math.PI) dLon = 2*Math.PI - dLon;
     var dist = Math.sqrt(dLat*dLat + q*q*dLon*dLon) * R;
     return dist.toPrecisionFixed(4);#// 4 sig figs reflects typical 0.3% accuracy of spherical model}/**
     #* Returns the bearing from this point to the supplied point along a rhumb line, in degrees *
     #* @param   {LatLon} point: Latitude/longitude of destination point
     #* @returns {Number} Bearing in degrees from North */
     LatLon.prototype.rhumbBearingTo = function(point) {
     var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
     var dLon = (point._lon-this._lon).toRad();
     var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
     if (Math.abs(dLon) > Math.PI) dLon = dLon>0 ? -(2*Math.PI-dLon) : (2*Math.PI+dLon);
     var brng = Math.atan2(dLon, dPhi);
     return (brng.toDeg()+360) % 360;}/**
     * Returns the destination point from this point having travelled the given distance (in km) on the
     * given bearing along a rhumb line 

     * @param   {Number} brng: Bearing in degrees from North
     * @param   {Number} dist: Distance in km
     * @returns {LatLon} Destination point
     
     LatLon.prototype.rhumbDestinationPoint = function(brng, dist) {
     var R = this._radius;
     var d = parseFloat(dist)/R;  # d = angular distance covered on earth's surface
     var lat1 = this._lat.toRad(), lon1 = this._lon.toRad();
     brng = brng.toRad();
     var lat2 = lat1 + d*Math.cos(brng);
     var dLat = lat2-lat1;
     var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
     var q = (!isNaN(dLat/dPhi)) ? dLat/dPhi : Math.cos(lat1); #E-W line gives dPhi=0
     var dLon = d*Math.sin(brng)/q;
     check for some daft bugger going past the pole
     if (Math.abs(lat2) > Math.PI/2) lat2 = lat2>0 ? Math.PI-lat2 : -(Math.PI-lat2);
     lon2 = (lon1+dLon+3*Math.PI)%(2*Math.PI) - Math.PI;
     return new LatLon(lat2.toDeg(), lon2.toDeg());}

never mind the last question - figured out where the method is -
problem with trying to do 2 things at the same time

for the rhumbDistanceTo
this is basically what the javascript is doing

import math

EARTHS_RADIUS = 6371 #Earth's mean radius in km

def rhumb_distance(point1, point2, radius=EARTHS_RADIUS):
    R = radius
    lat1 = math.radians(point1[0]) #could also be point1.latitude
    lat2 = math.radians(point2[0])
    #depends on if point1 is tuple or an object you define
    dLon = math.radians(abs(point2[1]-point1[1]))
    dLat = math.radians(poitn2[0]-point1[0])

    dPhi = math.log(math.tan(lat2/2+math.pi/4)/math.tan(lat1/2+math.pi/4))

    if dPhi: #make sure its nonzero
        q = dLat/dPhi
    else:
        q = math.cos(lat1)

    if dLon < math.pi:
        dLon = 2*math.pi - dLon
    dist = math.sqrt(dLat**2 + q**2*dLon*dLon) * R
    return dist
commented: Took the time to actually answer the question in a way I can understand +1

thank-you thank-you thank-you!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.