Generate random geocoordinates within a certain radius from the starting point

I use the following function to generate random geo-coordinates within a given radius from the starting point:

function randomGeo(center, radius) { var y0 = center.latitude; var x0 = center.longitude; var rd = radius / 111300; var u = Math.random(); var v = Math.random(); var w = rd * Math.sqrt(u); var t = 2 * Math.PI * v; var x = w * Math.cos(t); var y = w * Math.sin(t); var xp = x / Math.cos(y0); return { 'latitude': y + y0, 'longitude': xp + x0 }; } 

I do this in a loop, several times, using a radius of 2000 m and the following starting point:

 location: { // Oxford latitude: 51.73213, longitude: -1.20631 } 

I expect all of these results to be within 2,000 m; instead, I see values โ€‹โ€‹over 10,000 m:

 [ { latitude: 51.73256540025445, longitude: -1.3358092771716716 }, // 3838.75070783092 { latitude: 51.7214165686511, longitude: -1.1644147572878725 }, // 3652.1890457730474 { latitude: 51.71721400063117, longitude: -1.2082082568884593 }, // 8196.861603477768 { latitude: 51.73583824510363, longitude: -1.0940424351649711 }, // 5104.820455873758 { latitude: 51.74017571473442, longitude: -1.3150742602532257 }, // 4112.3279147866215 { latitude: 51.73496163915278, longitude: -1.0379454413532996 }, // 9920.01459343298 { latitude: 51.73582333121239, longitude: -1.0939302282840453 }, // 11652.160906253064 { latitude: 51.72145745285658, longitude: -1.2491630482776055 }, // 7599.550622138115 { latitude: 51.73036335927129, longitude: -1.3516902043395063 }, // 8348.276271205428 { latitude: 51.748104753808924, longitude: -1.2669212014250266 }, // 8880.760669882042 { latitude: 51.72010719621805, longitude: -1.327161328951446 }, // 8182.466715589904 { latitude: 51.725727610071125, longitude: -1.0691503599266818 } ] // 2026.3687763449955 

Given that I (shamelessly!) Plugged this solution from another place (although I saw several similar implementations), I canโ€™t understand where the math goes wrong.

(Also, in case you want it, this is how I calculate the distance. Pretty accurately, this is correct.)

 function distance(lat1, lon1, lat2, lon2) { var R = 6371000; var a = 0.5 - Math.cos((lat2 - lat1) * Math.PI / 180) / 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * (1 - Math.cos((lon2 - lon1) * Math.PI / 180)) / 2; return R * 2 * Math.asin(Math.sqrt(a)); } 
+6
source share
1 answer

The problem seems to be related to the fact that this is just an inaccurate calculation depending on which center you use. In particular, this line:

 var xp = x / Math.cos(y0); 

Delete this line and change the longitude to

 'longitude': x + x0 

It seems that all the points in the specified radius are preserved, although without this line it seems that in some cases the points will not be completely filled from east to west.

In any case, I found that someone is facing a similar problem here with someone elses Matlab code as a possible solution. Depending on how evenly distributed, you need random points if you want to work with a different formula.

The following is information on what happens to the formula provided:

 <!doctype html> <html> <head> <script type="text/javascript" src="//maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script> var distanceLimit = 2000; //in meters var numberRandomPoints = 200; var mapZoomLevel = 11; var locationindex = 0; var locations = [ {'name': 'Oxford, England', 'latitude': 51.73213, 'longitude': -1.20631}, {'name': 'Quito, Ecuador', 'latitude': -0.2333, 'longitude': -78.5167}, {'name': 'Ushuaia, Argentina', 'latitude': -54.8000, 'longitude': -68.3000}, {'name': 'McMurdo Station, Antartica', 'latitude': -77.847281, 'longitude': 166.667942}, {'name': 'Norilsk, Siberia', 'latitude': 69.3333, 'longitude': 88.2167}, {'name': 'Greenwich, England', 'latitude': 51.4800, 'longitude': 0.0000}, {'name': 'Suva, Fiji', 'latitude': -18.1416, 'longitude': 178.4419}, {'name': 'Tokyo, Japan', 'latitude': 35.6833, 'longitude': 139.6833}, {'name': 'Mumbai, India', 'latitude': 18.9750, 'longitude': 72.8258}, {'name': 'New York, USA', 'latitude': 40.7127, 'longitude': -74.0059}, {'name': 'Moscow, Russia', 'latitude': 55.7500, 'longitude': 37.6167}, {'name': 'Cape Town, South Africa', 'latitude': -33.9253, 'longitude': 18.4239}, {'name': 'Cairo, Egypt', 'latitude': 30.0500, 'longitude': 31.2333}, {'name': 'Sydney, Australia', 'latitude': -33.8650, 'longitude': 151.2094}, ]; </script> </head> <body> <div id="topbar"> <select id="location_switch"> <script> for (i=0; i<locations.length; i++) { document.write('<option value="' + i + '">' + locations[i].name + '</option>'); } </script> </select> <img src="http://google.com/mapfiles/ms/micons/ylw-pushpin.png" style="height:15px;"> = Center <img src="https://maps.gstatic.com/mapfiles/ms2/micons/red.png" style="height:15px;"> = No Longitude Adjustment <img src="https://maps.gstatic.com/mapfiles/ms2/micons/pink.png" style="height:15px;"> = With Longitude Adjustment (var xp = x / Math.cos(y0);) </div> <div id="map_canvas" style="position:absolute; top:30px; left:0px; height:100%; height:calc(100% - 30px); width:100%;overflow:hidden;"></div> <script> var markers = []; var currentcircle; //Create the default map var mapcenter = new google.maps.LatLng(locations[locationindex].latitude, locations[locationindex].longitude); var myOptions = { zoom: mapZoomLevel, scaleControl: true, center: mapcenter }; var map = new google.maps.Map(document.getElementById('map_canvas'), myOptions); //Draw default items var centermarker = addCenterMarker(mapcenter, locations[locationindex].name + '<br>' + locations[locationindex].latitude + ', ' + locations[locationindex].longitude); var mappoints = generateMapPoints(locations[locationindex], distanceLimit, numberRandomPoints); drawRadiusCircle(map, centermarker, distanceLimit); createRandomMapMarkers(map, mappoints); //Create random lat/long coordinates in a specified radius around a center point function randomGeo(center, radius) { var y0 = center.latitude; var x0 = center.longitude; var rd = radius / 111300; //about 111300 meters in one degree var u = Math.random(); var v = Math.random(); var w = rd * Math.sqrt(u); var t = 2 * Math.PI * v; var x = w * Math.cos(t); var y = w * Math.sin(t); //Adjust the x-coordinate for the shrinking of the east-west distances var xp = x / Math.cos(y0); var newlat = y + y0; var newlon = x + x0; var newlon2 = xp + x0; return { 'latitude': newlat.toFixed(5), 'longitude': newlon.toFixed(5), 'longitude2': newlon2.toFixed(5), 'distance': distance(center.latitude, center.longitude, newlat, newlon).toFixed(2), 'distance2': distance(center.latitude, center.longitude, newlat, newlon2).toFixed(2), }; } //Calc the distance between 2 coordinates as the crow flies function distance(lat1, lon1, lat2, lon2) { var R = 6371000; var a = 0.5 - Math.cos((lat2 - lat1) * Math.PI / 180) / 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * (1 - Math.cos((lon2 - lon1) * Math.PI / 180)) / 2; return R * 2 * Math.asin(Math.sqrt(a)); } //Generate a number of mappoints function generateMapPoints(centerpoint, distance, amount) { var mappoints = []; for (var i=0; i<amount; i++) { mappoints.push(randomGeo(centerpoint, distance)); } return mappoints; } //Add a unique center marker function addCenterMarker(centerposition, title) { var infowindow = new google.maps.InfoWindow({ content: title }); var newmarker = new google.maps.Marker({ icon: 'http://google.com/mapfiles/ms/micons/ylw-pushpin.png', position: mapcenter, map: map, title: title, zIndex: 3 }); google.maps.event.addListenerOnce(map, 'tilesloaded', function() { infowindow.open(map,newmarker); }); markers.push(newmarker); return newmarker; } //Draw a circle on the map function drawRadiusCircle (map, marker, distance) { currentcircle = new google.maps.Circle({ map: map, radius: distance }); currentcircle.bindTo('center', marker, 'position'); } //Create markers for the randomly generated points function createRandomMapMarkers(map, mappoints) { for (var i = 0; i < mappoints.length; i++) { //Map points without the east/west adjustment var newmappoint = new google.maps.LatLng(mappoints[i].latitude, mappoints[i].longitude); var marker = new google.maps.Marker({ position:newmappoint, map: map, title: mappoints[i].latitude + ', ' + mappoints[i].longitude + ' | ' + mappoints[i].distance + 'm', zIndex: 2 }); markers.push(marker); //Map points with the east/west adjustment var newmappoint = new google.maps.LatLng(mappoints[i].latitude, mappoints[i].longitude2); var marker = new google.maps.Marker({ icon: 'https://maps.gstatic.com/mapfiles/ms2/micons/pink.png', position:newmappoint, map: map, title: mappoints[i].latitude + ', ' + mappoints[i].longitude2 + ' | ' + mappoints[i].distance2 + 'm', zIndex: 1 }); markers.push(marker); } } //Destroy all markers function clearMarkers() { for (var i = 0; i < markers.length; i++) { markers[i].setMap(null); } markers = []; } $('#location_switch').change(function() { var newlocation = $(this).val(); clearMarkers(); mapcenter = new google.maps.LatLng(locations[newlocation].latitude, locations[newlocation].longitude); map.panTo(mapcenter); centermarker = addCenterMarker(mapcenter, locations[newlocation].name + '<br>' + locations[newlocation].latitude + ', ' + locations[newlocation].longitude); mappoints = generateMapPoints(locations[newlocation], distanceLimit, numberRandomPoints); //Draw default items currentcircle.setMap(null); drawRadiusCircle(map, centermarker, distanceLimit); createRandomMapMarkers(map, mappoints); }); </script> </body> </html> 
+13
source

All Articles