Get direction (compass) with two longitude/latitude points

33,536

Solution 1

O forgot to say I found the answer eventually. The application is to determine compass direction of a transit vehicle and its destination. Essentially, fancy math for acquiring curvature of Earth, finding an angle/compass reading, and then matching that angle with a generic compass value. You could of course just keep the compassReading and apply that as an amount of rotation for your image. Please note this is an averaged determination of the vehicle direction to the end point (bus station) meaning it can't know what the road is doing (so this probably best applies to airplanes or roller derby).

//example obj data containing lat and lng points
//stop location - the radii end point
endpoint.lat = 44.9631;
endpoint.lng = -93.2492;

//bus location from the southeast - the circle center
startpoint.lat = 44.95517;
startpoint.lng = -93.2427;

function vehicleBearing(endpoint, startpoint) {
    endpoint.lat = x1;
    endpoint.lng = y1;
    startpoint.lat = x2;
    startpoint.lng = y2;

    var radians = getAtan2((y1 - y2), (x1 - x2));

    function getAtan2(y, x) {
        return Math.atan2(y, x);
    };

    var compassReading = radians * (180 / Math.PI);

    var coordNames = ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"];
    var coordIndex = Math.round(compassReading / 45);
    if (coordIndex < 0) {
        coordIndex = coordIndex + 8
    };

    return coordNames[coordIndex]; // returns the coordinate value
}

ie: vehicleBearing(mybus, busstation) might return "NW" means its travelling northwesterly

Solution 2

I found some useful gps coordinates formula in math here. For this case, here my solution

 private double getDirection(double lat1, double lng1, double lat2, double lng2) {

    double PI = Math.PI;
    double dTeta = Math.log(Math.tan((lat2/2)+(PI/4))/Math.tan((lat1/2)+(PI/4)));
    double dLon = Math.abs(lng1-lng2);
    double teta = Math.atan2(dLon,dTeta);
    double direction = Math.round(Math.toDegrees(teta));
    return direction; //direction in degree

}
Share:
33,536
eav
Author by

eav

Updated on July 09, 2022

Comments

  • eav
    eav almost 2 years

    I'm working on a "compass" for a mobile-device. I have the following points:

    point 1 (current location): Latitude = 47.2246, Longitude = 8.8257
    point 2 (target  location): Latitude = 50.9246, Longitude = 10.2257
    

    Also I have the following information (from my android-phone):

    The compass-direction in degree, which bears to the north. 
    For example, when I direct my phone to north, I get 0°
    

    How can I create a "compass-like" arrow which shows me the direction to the point?

    Is there a mathematic-problem for this?

    EDIT: Okay I found a solution, it looks like this:

    /**
     * Params: lat1, long1 => Latitude and Longitude of current point
     *         lat2, long2 => Latitude and Longitude of target  point
     *         
     *         headX       => x-Value of built-in phone-compass
     * 
     * Returns the degree of a direction from current point to target point
     *
     */
    function getDegrees(lat1, long1, lat2, long2, headX) {
        
        var dLat = toRad(lat2-lat1);
        var dLon = toRad(lon2-lon1);
    
        lat1 = toRad(lat1);
        lat2 = toRad(lat2);
    
        var y = Math.sin(dLon) * Math.cos(lat2);
        var x = Math.cos(lat1)*Math.sin(lat2) -
                Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
        var brng = toDeg(Math.atan2(y, x));
    
        // fix negative degrees
        if(brng<0) {
            brng=360-Math.abs(brng);
        }
    
        return brng - headX;
    }
    
  • StaWho
    StaWho over 12 years
    or you can go all fancy and account for the curvature of the Earth
  • ericjam
    ericjam over 11 years
    That's a great description of an answer, try maybe providing a real example.
  • StaWho
    StaWho over 11 years
    @liquified - if you look the post, even before edit, it is not tagged with any language and the question asked is: Is there a mathematic-problem for this?. There is also no code supplied and apart from math tag there's also no other indication if OP would like to resolve it (amongst many) via, let's say real numbers trigonometry or complex numbers trigonometry. Given the ambiguous parameters of the question I think the answer is sufficient.
  • user2071152
    user2071152 over 8 years
    @liquified, sorry am unable to understand why (compassReading / 45) is being done. Could you please let me know. Thanks.
  • ericjam
    ericjam over 8 years
    45 is 45 degree intervals of the compass, correlating to the 9 coordNames (human names) of the compass array (NSEW,etc). Dividing your compassReading by 45 gives you, in the range of 360 degrees, how close your reading is to one of those intervals (Math.round). 360 / 45 for example gives you 8 which is the 8th index in the array or "N". You could modify this if you wanted only NSEW by dividing by 90 instead
  • Mandeep Janjua
    Mandeep Janjua almost 5 years
    @efwjames " correlating to the 9 coordNames " - 45*8=360. You have repeated "N" twice in your coordNames array. Please remove that.
  • allez l'OM
    allez l'OM over 2 years
    I vote for this answer, and give you my slightly shortened version (I like arrays, and more winds): const cardinals = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","W‌​SW","W","WNW","NW","‌​NNW","N"]; const carDirect = (x0,y0, x1,y1) => Math.round( Math.atan2((x1-x0),(y1-y0)) * (8 / Math.PI) ); const cardIndex = (dir) => dir<0 ? dir+16 : dir; console.log(cardinals[cardIndex(carDirect( start_lng,start_lat, end_lng,end_lat))]); Thank you.