Skip to content

Commit

Permalink
Merge pull request #27 from doublestranded/bearing-destination
Browse files Browse the repository at this point in the history
Bearing destination
  • Loading branch information
fredericbonifas committed May 4, 2015
2 parents 0f04b78 + 04ebef6 commit a0ebd04
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
50 changes: 50 additions & 0 deletions dist/leaflet.geometryutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,56 @@ L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
x2 = Math.cos(angleRad)*(pPoint.x-pCenter.x) - Math.sin(angleRad)*(pPoint.y-pCenter.y) + pCenter.x,
y2 = Math.sin(angleRad)*(pPoint.x-pCenter.x) + Math.cos(angleRad)*(pPoint.y-pCenter.y) + pCenter.y;
return map.unproject(new L.Point(x2,y2), maxzoom);
},

/**
Returns the bearing in degrees clockwise from north (0 degrees)
from the first L.LatLng to the second.
@param {L.LatLng} latlng1: origin point of the bearing
@param {L.LatLng} latlng2: destination point of the bearing
@returns {float} degrees clockwise from north.
*/
bearing: function(latlng1, latlng2) {
var rad = Math.PI / 180,
lat1 = latlng1.lat * rad,
lat2 = latlng2.lat * rad,
lon1 = latlng1.lng * rad,
lon2 = latlng2.lng * rad,
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
x = Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);

var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
return bearing >= 180 ? bearing-360 : bearing;
},

/**
Returns the point that is a distance and heading away from
the given origin point.
@param {L.LatLng} latlng: origin point
@param {float}: heading in degrees, clockwise from 0 degrees north.
@param {float}: distance in meters
@returns {L.latLng} the destination point.
*/
destination: function(latlng, heading, distance) {
heading = (heading + 360) % 360;
var rad = Math.PI / 180,
radInv = 180 / Math.PI,
R = 6378137, // approximation of Earth's radius
lon1 = latlng.lng * rad,
lat1 = latlng.lat * rad,
rheading = heading * rad,
sinLat1 = Math.sin(lat1),
cosLat1 = Math.cos(lat1),
cosDistR = Math.cos(distance / R),
sinDistR = Math.sin(distance / R),
lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 *
sinDistR * Math.cos(rheading)),
lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR *
cosLat1, cosDistR - sinLat1 * Math.sin(lat2));
lon2 = lon2 * radInv;
lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2;
return L.latLng([lat2 * radInv, lon2]);
}
});

Expand Down
62 changes: 62 additions & 0 deletions test/test.geometryutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,65 @@ describe('Point rotation', function() {
done();
});
});

describe('Compute Bearing', function() {

it('It should be degrees clockwise from north, 0 degrees.', function(done) {
var latlng1 = L.latLng([0.0, 0.0]),
latlng2 = L.latLng([90.0, 0.0]);
assert.equal(0.0, L.GeometryUtil.bearing(latlng1,latlng2));
done();
});

it('Same point, should be zero.', function(done) {
var latlng1 = L.latLng([0.0, 0.0]),
latlng2 = L.latLng([0.0, 0.0]);
assert.equal(0, L.GeometryUtil.bearing(latlng1,latlng2));
done();
});

it('Crossing Prime Meridian.', function(done) {
var latlng1 = L.latLng([10.0, -10.0]),
latlng2 = L.latLng([-10.0, 10.0]);
assert.equal(134.5614514132577, L.GeometryUtil.bearing(latlng1,latlng2));
done();
});

it('Negative value for bearing greater than / equal to 180', function(done) {
var latlng1 = L.latLng([33.0, -120.0]),
latlng2 = L.latLng([34.0, -122.0]);
assert.equal(-58.503883697887375, L.GeometryUtil.bearing(latlng1,latlng2));
done();
});

});

describe('Destination', function() {

it('It should be [90.0,0.0]', function(done) {
var latlng1 = L.latLng([0.0, 0.0]),
heading = 0.0;
dist = 6378137 * Math.PI / 2.0; // 1/4 Earth's circumference.
result = L.latLng([90.0,0.0]);
assert.latLngEqual(result, L.GeometryUtil.destination(latlng1, heading, dist));
done();
});

it('Crossing the International Date Line', function(done) {
var latlng1 = L.latLng([0.0, -175.0]),
heading = -90.0;
dist = 6378137 * Math.PI / 8.0;
result = L.latLng([0.0, 162.5]);
assert.latLngEqual(result, L.GeometryUtil.destination(latlng1, heading, dist));
done();
});

it('Crossing the Prime Meridian', function(done) {
var latlng1 = L.latLng([10.0, -10.0]),
heading = 134.5614514132577;
dist = 3140555.3283872544;
result = L.latLng([-10, 10.0]);
assert.latLngEqual(result, L.GeometryUtil.destination(latlng1, heading, dist));
done();
});
});

0 comments on commit a0ebd04

Please sign in to comment.