Próbuję utworzyć losowe lokalizacje w pobliżu mojej lokalizacji. Chcę stworzyć losowe pary szerokości i długości geograficznej wewnątrz 200-metrowego okręgu otaczającego moją lokalizację.
Oto formuła, którą wymyśliłem (z pomocą ludzi z StackOverFlow): (Losowa liczba od -1 do 1) * promień + (stara długość geograficzna) = nowa długość w promieniu starej długości geograficznej
(Liczba losowa od -1 do 1) * promień + (stara szerokość geograficzna) = nowa szerokość w promieniu starej szerokości geograficznej
Chodzi o to, że coś dziwnego dzieje się z moją implementacją, ponieważ wszystkie losowe lokalizacje znajdują się zbyt blisko centrum lokalizacji, wydaje się, że formuła nie obejmuje całego promienia.
Masz pojęcie, co może być nie tak z moją formułą?
Edytowane, aby pokazać bieżącą implementację Java:
public static Location getLocation(Location location, int radius) {
Random random = new Random();
// Convert radius from meters to degrees
double radiusInDegrees = radius / METERS_IN_DEGREES;
double x0 = location.getLongitude() * 1E6;
double y0 = location.getLatitude() * 1E6;
double u = random.nextInt(1001) / 1000;
double v = random.nextInt(1001) / 1000;
double w = radiusInDegrees * Math.sqrt(u);
double t = 2 * Math.PI * v;
double x = w * Math.cos(t);
double y = w * Math.sin(t);
// Adjust the x-coordinate for the shrinking of the east-west distances
double new_x = x / Math.cos(y0);
// Set the adjusted location
Location newLocation = new Location("Loc in radius");
newLocation.setLongitude(new_x + x0);
newLocation.setLatitude(y + y0);
return newLocation;
}
Nie jestem pewien, co robię źle, ponieważ nowe lokalizacje są tworzone na środku morza.
Dowolny pomysł?
źródło
random.nextInt(1001)/1000
zwróci wartość większą niż 1 przez około 0,1% czasu. Dlaczego nie używaszrandom.nextDouble
lubrandom.nextFloat
? (ii) Mnożeniex0
iy0
przez1E6
jest raczej tajemnicze; nie wydaje się, aby przyniosło prawidłowe wyniki.Odpowiedzi:
Jest to trudne z dwóch powodów: po pierwsze, ograniczenie punktów do koła zamiast kwadratu; po drugie, uwzględniając zniekształcenia w obliczeniach odległości.
Wiele GIS zawiera funkcje, które automatycznie i transparentnie obsługują oba powikłania. Jednak tagi tutaj sugerują, że pożądany może być niezależny od GIS opis algorytmu.
Aby wygenerować punkty równomiernie, losowo i niezależnie w okręgu o promieniu r wokół lokalizacji (x0, y0), zacznij od wygenerowania dwóch niezależnych jednorodnych wartości losowych u i v w przedziale [0, 1). (Właśnie to zapewnia prawie każdy generator liczb losowych.) Oblicz
Pożądany punkt losowy znajduje się w miejscu (x + x0, y + y0).
Gdy używasz współrzędnych geograficznych (lat, lon), wówczas x0 (długość geograficzna) i y0 (szerokość geograficzna) będą wyrażone w stopniach, ale r najprawdopodobniej będzie wyrażone w metrach (stopach lub milach lub w innym pomiarze liniowym). Najpierw zamień promień r na stopnie , jakbyś znajdował się w pobliżu równika. Tutaj jest około 111 300 metrów na stopień.
Po drugie, po generowanie X i Y , jak w punkcie (1), wyregulować współrzędna x dla kurczenia odległościach Wschód-Zachód:
Pożądany punkt losowy znajduje się w miejscu (x '+ x0, y + y0). To jest przybliżona procedura. W przypadku małych promieni (mniejszych niż kilkaset kilometrów), które nie rozciągają się nad żadnym biegunem ziemi, zwykle będzie tak dokładna, że nie można wykryć żadnego błędu, nawet podczas generowania dziesiątek tysięcy losowych punktów wokół każdego centrum (x0, y0) .
źródło
Zaimplementowane dla Javascript:
źródło
Prawidłowa implementacja to:
Usunąłem zależność od bibliotek zewnętrznych, aby była bardziej dostępna.
źródło
Akceptowana odpowiedź i pochodne nie działały dla mnie. Wyniki były bardzo niedokładne.
Prawidłowa implementacja w javascript:
Pełna treść tutaj
W przyjętej odpowiedzi stwierdziłem, że punkty są rozmieszczone w elipsie o szerokości 1,5 razy większej niż wysokość (w Panamie) i 8 razy większej (wysokość na północy Szwecji). Jeśli usunęłem korektę współrzędnych x z odpowiedzi @ Whubera, elipsa jest zniekształcona w drugą stronę, 8 razy większa niż jej szerokość.
Kod w mojej odpowiedzi został oparty na algorytmach stąd
Poniżej widać dwa jsfiddle, które pokazują problem z elipsą rozciągającą
Prawidłowy algorytm
Zniekształcony algorytm
źródło
whuberPointAtDistance()
:x1 = (w * Math.cos(t)) / Math.cos(y0 * (Math.PI / 180))
.W Pythonie
Wydajność
Odległość między punktami wynosi 0,288044147914 Odległość między punktami wynosi 0,409557451806 Odległość między punktami wynosi 0,3668260305716 Odległość między punktami wynosi 0,340720560546 Odległość między punktami wynosi 0,453773334731 Odległość między punktami wynosi 0,460608754561 Odległość między punktami wynosi 0,4797188825576 Odległość między punktami wynosi 0,603178188859 Odległość między punktami wynosi 0,603178188859 Odległość między punktami wynosi 0,603178188859 Odległość między punktami wynosi 0,503691568896 Odległość między punktami wynosi 0,175153349209 Odległość między punktami wynosi 0,195149463735 Odległość między punktami wynosi 0,424094009858 Odległość między punktami wynosi 0,286807741494 Odległość między punktami wynosi 0,558049206307 Odległość między punktami wynosi 0,498612171417 Odległość między punktami wynosi 0,04734471821523
źródło
Można sprawdzić wyniki swoich obliczeń tutaj . Przewiń w dół do sekcji o nazwie „Punkt docelowy na podstawie odległości i namiaru od punktu początkowego”. Na dole jest nawet prosta formuła JavaScript, aby to zaimplementować. Nadal będziesz musiał wygenerować losowe łożysko $ \ theta $ w radianach (mierzone zgodnie z ruchem wskazówek zegara od północy), choć powinno to być dość proste. Wzory te zakładają kulistą ziemię (chociaż jest elipsoidalna), co jest wystarczająco dobre, ponieważ powoduje błędy do 0,3%.
źródło
Wdrożenie dla Swift
Pobieranie lat i lng z geoencodera i przekazywanie go do tej funkcji
W powyższym przykładzie otrzymuję szerokość i długość geograficzną z geograficznego kodowania nazwy kraju, ponieważ za każdym razem nazwa kraju podaje tę samą szerokość i długość geograficzną, tak samo jak w środku kraju, więc potrzebowałem losowości.
źródło
private void drawPolyline (double lat, double lng) {
źródło