brucemcpherson / desktopliberation

hosting for desktop liberation google plus community
30 stars 1 forks source link

Question - Caculate lat/lon from distance #12

Open littlewing1977 opened 5 years ago

littlewing1977 commented 5 years ago

How are you figuring the "Heading Angle" for use with the function mentioned? In the example, it uses -135 as the heading. I see the VBA code converts to radians, so the heading must be measured in degrees, but why is it negative? So far, I have worked with heading in two ways. One is like a compass; 0-360degrees. The other is based from North or South; 0-90degrees.

brucemcpherson commented 5 years ago

can you point me to the page you are referring to. It's quite some years since I've looked at those.

littlewing1977 commented 5 years ago

http://ramblings.mcpher.com/Home/excelquirks/getmaps/trig

brucemcpherson commented 5 years ago

I don't have anything with Excel on it right now to check, but the calculations are done in radians, and bearing is expressed in degrees. Because arctangents are expressed from -180 to 180, I just leave them like that. Its' straightforward to convert that to a compass heading with

compass = (bearing+360) mod 360

Here's some JavaScript and some examples, that do the same things

const MapMath = (() => {
  const toRadians = degrees => degrees * Math.PI / 180;
  const toDegrees = radians => radians * 180 / Math.PI;
  const earthRadius = 6371
  // calculate distance between 2 points
  const getDistance = ({ from, to }) => {
    const latDelta = toRadians(to.lat-from.lat)
    const lngDelta = toRadians(to.lng-from.lng)
    const fromLatRad = toRadians(from.lat)
    const toLatRad = toRadians(to.lat)

    const a =  Math.sin(latDelta/2) * Math.sin(latDelta/2) +
        Math.cos(fromLatRad) * Math.cos(toLatRad) *
        Math.sin(lngDelta/2) * Math.sin(lngDelta/2);

    return earthRadius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
  }
  // given 2 lat lng, caclulate bearing
  const getBearing = ({ from, to }) => {
    const b = Math.sin(to.lat - from.lat) * Math.cos(to.lng);
    const a =
      Math.cos(from.lng) * Math.sin(to.lng) -
      Math.sin(from.lng) * Math.cos(to.lng) * Math.cos(to.lat - from.lat);
    const bearing = Math.atan2(b, a);
    return {
      radians: bearing,
      degrees: toDegrees(bearing),
      compass: (toDegrees(bearing)+360) % 360
    };
  };
  return {
    toRadians,
    toDegrees,
    getBearing,
    earthRadius,
    getDistance
  };
})();

const aberdeen = { name: "Aberdeen", lat: 57.149651, lng: -2.099075 };
const london = { name: "London", lat: 51.509865, lng: -0.118092 };
const ny = { name: "New York", lat: 40.71427, lng: -74.00597 };
const rio = { name: "Rio de Janeiro", lat: -22.752754, lng: -42.864876 };
const sydney = { name: "Sydney", lat: -33.865143, lng: 151.209900 };

const showMapMath = ({ from, to }) => {
  console.log({
    from: from.name,
    to: to.name,
    bearing: MapMath.getBearing({ from, to }),
    distance: MapMath.getDistance ({ from , to })
  });
};

showMapMath({ from: london, to: aberdeen });
showMapMath({ to: london, from: aberdeen });
showMapMath({ to: london, from: ny });
showMapMath({ to: ny, from: london });
showMapMath({ from: ny, to: london });
showMapMath({ to: ny, from: rio });
showMapMath({ from: ny, to: rio });
showMapMath({ to: london, from: rio });
showMapMath({ from: london, to: rio });
showMapMath({ to: london, from: sydney });
showMapMath({ from: london, to: sydney });