[ConnectIQ Feature Request] Location Comparison (Haversine)

Former Member
Former Member
It seems to me that a GPS watch is probably doing haversine calculations pretty much constantly, there must be a pretty highly optimized version of the formula in my watch somewhere already. It would be nice to be able to access that to compare positions rather than writing my own implementation of Haversine or just subtracting some constants from the decimal lat/lng.

Just a thought, it'd be a nice little feature, probably just exposed as Location.compare(Location) ...

-Rob
  • Former Member
    Former Member over 9 years ago
    hyakuhei doesn't do maths so good.... :p
  • What kind of compare are you looking to do? See if lan/lon are the same? Get the distance been position 1 and position 2? the direction from 1 to 2?

    Planetscooter posted code to do the distance a while back, and I'm using it, and it works well. With that, I can see if I'm back to a known location using a current GPS location, for example (I actually use "within 75" for my application).
  • Former Member
    Former Member over 9 years ago
    What kind of compare are you looking to do? See if lan/lon are the same? Get the distance been position 1 and position 2? the direction from 1 to 2?


    Thanks Jim! I'm just trying to find the distance between two spots.

    In fact I have a working, though somewhat verbose Haversine function here:

    function haversine(position1, position2){
    //credit: www.movable-type.co.uk/.../latlong.html
    //credit: rosettacode.org/.../Haversine_formula
    var radius = 6371000; //Eaths radius in meters
    var p1LatRads = position1.toRadians()[0];
    var p2LatRads = position2.toRadians()[0];

    var latDeltaDegrees = position2.toDegrees()[0] - position1.toDegrees()[0]; // The difference of the two latitudes in degrees
    var latDeltaLocation = new Position.Location({:latitude=>latDeltaDegrees, :longitude=>0, :format=>:degrees}); // An object that uses that lat difference so we can get radians from it
    var latDeltaRads = latDeltaLocation.toRadians()[0];

    var lngDeltaDegrees = position2.toDegrees()[1] - position1.toDegrees()[1];
    var lngDeltaLocation = new Position.Location({:latitude=>0, :longitude=>lngDeltaDegrees, :format=>:degrees});
    var lngDeltaRads = lngDeltaLocation.toRadians()[1];

    var a = Math.sin(latDeltaRads / 2) * Math.sin(latDeltaRads / 2) + Math.sin(lngDeltaRads/2) * Math.sin(lngDeltaRads/2) * Math.cos(p1LatRads) * Math.cos(p2LatRads);

    var c = 2 * Math.asin(Math.sqrt(a));
    var result = radius * c;

    return result; //result is in meters
    }



    I just think it's something that lots of applications are going to want this functionality and putting into a Location.compare() seems like a reasonable thing to do.
  • Here's planetscooter's code.... Not sure exactly the method he's using, but it works for me (I changed it a bit so that lat/lon is passed differently and distance is returned as a number.

    // computes the direct distance between two points
    // distance = sqrt(dx * dx + dy * dy)
    // with distance: in km
    // dx = 111.3 * cos(lat) * (lon1 - lon2)
    // lat = (lat1 + lat2) / 2 * 0.01745
    // dy = 111.3 * (lat1 - lat2)
    // lat1, lat2, lon1, lon2: Breite, Länge in Grad
    // 1° = p/180 rad ˜ 0.01745
    function computeDistance (pos1, pos2) {
    var lat1, lat2, lon1, lon2, lat, lon;
    var dx, dy, distance;

    lat1 = pos1.toDegrees()[0].toFloat();
    lon1 = pos1.toDegrees()[1].toFloat();
    lat2 = pos2.toDegrees()[0].toFloat();
    lon2 = pos2.toDegrees()[1].toFloat();

    lat = (lat1 + lat2) / 2 * 0.01745;
    dx = 111.3 * Math.cos(lat) * (lon1 - lon2);
    dy = 111.3 * (lat1 - lat2);
    distance = 1000 * Math.sqrt(dx * dx + dy * dy);
    distance = distance.toNumber();
    strokelength = Lang.format("$1$ m", [distance]);
    validstrokeposition = true;
    Sys.println(strokelength);
    }
  • Former Member
    Former Member over 9 years ago
    Looks good :)
  • Planetscooter's code is what the haversine formula reduces to for points which are very close together (so cos(lat) is effectively the same for both points, and sin(lon1-lon2) is effectively equal to (lon1-lon2)). Which is good to 0.005% when lon1 and lon2 are a full degree apart, which is over 100km for latitude and nearly 30km for longitude even at 75 north/south. There aren't many human-powered activities where this approximation isn't perfectly good (maybe a 24-hour point to point cycle race in a straight line?)

    I agree with Hyakuhei's suggestion, though, you'd imagine all the watches have a hardware calculation for this, as a reasonably complicated calculation they're doing at least once a second, and probably considerably more if you are following a course.
  • I'll file this as a new feature request. We plan to make navigation and mapping features available in the SDK in future releases (no ETA, and I don't have any specifics), so this will likely be part of that.
  • Former Member
    Former Member over 9 years ago
    Thanks Brandon, it seems like a sensible thing to add :)
  • Am wondering just how processor intensive are this calculation if I were to do it once every second?
    How to determine?