2015-07-02 7 views
6

I die folgenden Funktion bin mit Zufall geo zum Erzeugen von einem Saatpunkt innerhalb eines bestimmten Radius Koordinaten:zufällige Geokoordinaten innerhalb bestimmten Radius von Saatpunkt

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 dies in einer Schleife, mehrmals unter Verwendung eines Radius von 2000 m und des folgenden Startpunkts:

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

Ich würde erwarten, dass alle diese Ergebnisse innerhalb von 2000 m liegen; stattdessen ich sehe Werte nach oben von 10000m:

[ { 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 

Da ich (schamlos!), diese Lösung von anderswo plagiiert (wenn auch ich mehrere ähnliche Implementierungen gesehen habe), kann ich nicht zu Figur scheinen heraus, wo die Mathematik falsch läuft.

(auch, falls Sie es wünschen, das ist, wie ich den Abstand bin zu berechnen. Ziemlich sicher, dass dies richtig ist.)

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)); 
} 
+1

Sie hatten, durch Zufall, nehmen Sie es von hier aus? https://gist.github.com/mkhatib/5641004 –

+0

Nicht da, aber das sieht genauso aus wie meine lol – brandonscript

Antwort

13

Das Problem aus der Tatsache, Einhalt zu gebieten scheint, dass dies nur eine ungenaue Berechnung abhängig davon, welchen Mittelpunkt Sie verwenden. Besonders diese Linie:

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

diese Zeile aus- und Längen

Ändern
'longitude': x + x0 

Scheint alle Punkte innerhalb des angegebenen Radius zu halten, obwohl ohne diese Linie scheint es, die Punkte nicht vollständig ausfüllen von Ost nach West in einigen Fällen.

Wie auch immer, ich habe jemanden gefunden, der ein ähnliches Problem here mit jemand anderen Matlab-Code als eine mögliche Lösung erlebt. Abhängig davon, wie gleichmäßig verteilt Sie die Zufallspunkte benötigen, wenn Sie mit einer anderen Formel arbeiten möchten.

Hier ist ein Google Maps visualisieren, was mit Ihrer versehenen Formel los:

<!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>

+0

So weit so gut, danke! Neugierig, warum es sich immer noch nicht von Ost nach West füllt? Aber es scheint sich jetzt korrekt zu verhalten. – brandonscript

+0

Mein Verständnis ist, dass Ihre Formel funktionieren würde, wenn die Erde eine perfekte Kugel wäre :) Dieses Bit, das ich entfernte, ist ein Versuch, die Erde zu kompensieren, die keine perfekte Kugel ist, aber es funktioniert nicht überall auf dem Globus. – webworker01

+0

Ahh, du hast wahrscheinlich recht. Frage mich, ob wir das kompensieren könnten? Wahrscheinlich zu kompliziert für das, was ich versuche zu tun lol – brandonscript

Verwandte Themen