Skip to content

Instantly share code, notes, and snippets.

@siberex
Last active September 13, 2016 06:35
Show Gist options
  • Save siberex/95afb52ba438c189ccac1a6cc8d59e30 to your computer and use it in GitHub Desktop.
Save siberex/95afb52ba438c189ccac1a6cc8d59e30 to your computer and use it in GitHub Desktop.
Random locations nearby specified location limited by radius
/**
* Get random geo point [latitude, longitude] within some distance from specified geo point (lat, long)
*
* Points will be uniformly-distributed on multiple calls.
*
* → Demo is here: http://jsfiddle.net/siberex/f72ffn1x/
*
* @param lat Latitude in degrees
* @param lng Longitude in degrees
* @param distance Distance in meters to limit point distribution to.
* If negative value is provided, points will be generated on exact distance (e.g. on circle border).
* @returns {*[]} Array with [latitude, longitude]
*
* @author Stepan Legachev <me@sib.li>
*/
exports.getRandomLocation = function(lat, lng, distance = 10000) {
// Convert to radians
lat *= Math.PI / 180;
lng *= Math.PI / 180;
var radius;
// Distance should be set in meters, negative for exact distance
if (distance < 0) {
// Exact distance
radius = Math.abs(distance);
} else {
// Get uniformly-random distribution within peovided distance
// http://stackoverflow.com/questions/5837572/generate-a-random-point-within-a-circle-uniformly
radius = Math.random() + Math.random();
radius = radius > 1 ? 2 - radius : radius;
radius *= distance ? distance : 10000; // multiply by distance meters
}
// Convert radius from meters to degrees to radians
// 111319.9 meters = one degree along the equator
radius /= 111319.9;
// Correction for the actual distance from equator is NOT needed here
// radius *= Math.cos(lat);
// Convert to radians
radius *= Math.PI / 180;
// Random angle
var angle = Math.random() * Math.PI * 2;
// Get a point {nLat,nLng} in a distance={radius} out on the {angle} radial from point {lat,lng}
// http://williams.best.vwh.net/avform.htm#LL
var nLng,
nLat = Math.asin( Math.sin(lat) * Math.cos(radius) + Math.cos(lat) * Math.sin(radius) * Math.cos(angle) );
if (Math.cos(nLat) == 0) {
nLng = lng;
} else {
nLng = (lng - Math.asin( Math.sin(angle) * Math.sin(radius) / Math.cos(nLat) ) + Math.PI) % (Math.PI * 2) - Math.PI
}
// Convert to degrees
nLat *= 180 / Math.PI;
nLng *= 180 / Math.PI;
return [nLat, nLng];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment