Jak obliczyć obwiednię dla danej odległości i szerokości / długości geograficznej


13

Muszę być w stanie obliczyć ramkę ograniczającą lub okrąg dla danej szerokości geograficznej WGS84 i długości geograficznej WGS84 oraz odległości, ale nie mam pojęcia, od czego zacząć!

Odległość od startu Lat / Lon wynosiłaby 10 km lub mniej.

Czy ktoś mógłby dać mi wskazówki / przykład, jak to zrobić


Dla środowisk, które nie pokrywają albo słup, szczegółowa odpowiedź jest podana na gis.stackexchange.com/questions/19221/... . Ale to nie jest pełna historia, jak sugerują obecne odpowiedzi: możesz dokonać kompromisu złożoności programu szybkość-dokładność-program. Zauważ też, że podczas pracy w trybie lat-lon występuje problem „zawijania” podczas określania obwiedni (trudności występują w południku + -180 stopni). Aby znaleźć rozwiązanie tego problemu, zobacz gis.stackexchange.com/questions/17788/… .
whuber

Czy naprawdę potrzebujesz pudełka, czy wystarczyłyby 4 punkty w pobliżu danego punktu? Biorąc pod uwagę punkt p, znajdź 4 punkty d odległość w kierunkach NE, SW, SE i NW od p.
Kirk Kuykendall

@Kirk - Jeśli masz współrzędne 4 punktów, to masz pudełko ...
martinstoeckli

@martinstoeckli racja, miałem tylko nadzieję uprościć problem, nie musząc wizualizować, jak wygląda pudełko rzutowane na kulę. Należy również zauważyć, że problem można uogólnić, aby wyjaśnić, że boki skrzynki nie muszą spadać na tę samą szerokość / długość geograficzną (innymi słowy obrócone pole).
Kirk Kuykendall

@Kirk - Ach, cóż, jeśli potrzebujesz tego dokładnie, to oczywiście masz rację. Myślę, że pudełko jest przydatne tylko do szybkiego znalezienia potencjalnych kandydatów. Aby sprawdzić, czy dwa punkty znajdują się w pewnej odległości (okręgu), można zastosować bardziej złożoną formułę haverine.
martinstoeckli

Odpowiedzi:


15

WGS-co? WGS-84? W zależności od tego, jakiej dokładności potrzebujesz, możesz potrzebować dużo więcej informacji - domyślam się, że właśnie dlatego zostałeś odrzucony, chociaż nikt nie zadał sobie trudu, aby zostawić komentarz mówiący dlaczego.

Oto dwa sposoby:

Niedokładne, ale prawdopodobnie „wystarczająco dobre”

Jeden stopień szerokości geograficznej wynosi około 10001,9.965729 / 90 kilometrów (odległość od równika do bieguna, podzielona przez dziewięćdziesiąt stopni) lub 111,113 kilometrów, przy zastosowaniu układu odniesienia WGS-84. Jest to przybliżenie ze względu na kształt ziemi i ponieważ odległości zmieniają się w miarę zbliżania się do biegunów (jeden powód, aby używać szerokości, a nie długości geograficznej - ostatecznie odległość jednego stopnia długości geograficznej wynosi zero!) Ziemia również nie jest idealna kula. Oba są powodem, dla którego w mojej drugiej odpowiedzi należy zastosować bardziej złożone podejście oparte na projekcji i danych.

10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees

To używa stopni dziesiętnych, a nie stopni / minut / sekund.

Tak więc obwiednia będzie punktem, plus minus 0,08999 stopni. Alternatywnie możesz użyć tej liczby jako promienia, dając ci okrąg ograniczający .

Każda osoba czytająca GIS będzie drżeć. Będzie to jednak głównie dokładne, w zależności od tego, gdzie jesteś na świecie. Dla promienia 10 km powinno być dobrze.

Znacznie dokładniejszy, ale więcej kodu

Użyj biblioteki projekcji i podaj dane, itp. Polecam Proj4; jest szeroko stosowany, więc Google zwraca mnóstwo wyników z pytaniami na ten temat, a są też opakowania Delphi . Jeśli masz problemy z korzystaniem z niego, opublikuj kolejne pytanie tutaj na SO - to nie wchodzi w zakres tego pytania. Witryna Proj4 zawiera przykłady wykorzystujące podstawowe interfejsy API i chociaż są one w C, powinny być dość łatwe do przetłumaczenia. Ich odniesienie API jest najlepszym miejscem do rozpoczęcia, a następnie FAQ .

Użyłbym WGS-84 jako podstawowego układu odniesienia (reprezentacji Ziemi), chyba że znasz konkretny, którego chcesz użyć lub który został wykorzystany do utworzenia twoich współrzędnych. Jest powszechnie używany i dość dokładny.

Jeśli twoja pozycja pochodzi z Map Google (na przykład), określ rzut Mercator. Możesz użyć innej projekcji lub użyć, powiedzmy, współrzędnych UTMzamiast szerokości i długości geograficznej, w zależności od źródła danych i jeśli chcesz wysokiej dokładności dla małego obszaru lokalnego. (UTM ma wiele stref, z których każda zmienia zniekształcenie, dzięki czemu wewnątrz tej strefy jest bardzo dokładna; jeśli użyjesz strefy dla współrzędnych poza nią, zniekształcenie znacznie wzrośnie, gdy odsuniesz się. Jeśli zobaczysz całą ziemię rzutowaną z jednej strefa, może być nierozpoznawalna. Ale w obrębie strefy tłumaczenia UTM będą tak dobre, jak to tylko możliwe. Współrzędne są ogólnie określone w metrach, a nie w stopniach, więc może być bardziej przydatne dla ciebie, biorąc pod uwagę, że potrzebujesz 10 km promień. 10 km jest łatwo w obrębie jednej strefy, wystarczy wybrać odpowiednią strefę na podstawie współrzędnej środka. Jedynym trudnym zagadnieniem jest zbliżenie się do granicy: jest to powszechna sytuacja i jest w porządku, po prostu bądźspójny w sposobie wyboru, którego używasz . Proj4 pozwoli ci także na tłumaczenie rzutów, dzięki czemu możesz przejść z Mercator WGS-84 lat / long do strefy UTM n , na przykład, lub do dwóch stref UTM).


2
W miejscu, w którym mieszkamy, geodeta powiedział mi kiedyś, że do obliczeń mentalnych używa 1 stopnia w przybliżeniu 108 km. Psychicznie 10 km to około 0,1 stopnia. Ponieważ są to przybliżone przybliżenia, najlepiej traktować je z dokładnością do 1 cyfry znaczącej (maksymalnie 2 lub 3) zamiast 0,089982311915998, ponieważ oznacza to poziom precyzji.
Stephen Quan

1
Naprawdę nie jest trudno obliczyć stopnie dokładniej, biorąc pod uwagę szerokość geograficzną. Ponieważ komputer dokonuje obliczeń, przybliżenie nic nie zyskuje (patrz pierwsza funkcja w moim przykładzie).
martinstoeckli

3

Zakładając, że chcesz wykonać zapytanie w bazie danych, prawdopodobnie chcesz przeprowadzić szybkie (niedokładne) wyszukiwanie, a następnie dokładnie obliczyć odległość dla powstałych miejsc. Czy to twój scenariusz?

Następująca funkcja (w PHP przepraszam) z grubsza obliczy różnice w szerokości i długości geograficznej. Różnice te zależą od szerokości geograficznej punktu wyszukiwania. Użyj ich (z małą tolerancją), aby szybko przeszukać bazę danych. Pole można obliczyć po prostu za pomocą szerokości i szerokości geograficznej -deltaLatitude oraz długości i długości geograficznej + -deltaLongitude.

deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])

/**
 * Calculates the deltas in latitude and longitude to use, for a db search
 * around a location in the database.
 * @param float $distance Radius to use for the search [m]
 * @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
 * @param float $deltaLatitude Calculated delta in latitude [deg]
 * @param float $deltaLongitude Calculated delta in longitude [deg]
 * @param float $earthRadius Mean earth radius in [m]
 */
public static function angleFromSphericDistance($distance, $latitude,
  &$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
  $lat = deg2rad($latitude);

  $radiusOnLatitude = cos($lat) * $earthRadius;
  $deltaLatitude = $distance / $earthRadius;
  $deltaLongitude = $distance / $radiusOnLatitude;

  $deltaLatitude = rad2deg($deltaLatitude);
  $deltaLongitude = rad2deg($deltaLongitude);
}

Dzięki formule haverine możesz obliczyć odległości na kuli. Użyj go dla każdego ze znalezionych miejsc, aby uzyskać „dokładną” odległość. W ten sposób możesz sprawdzić, czy dwa miejsca znajdują się w określonym promieniu (koło zamiast pudełka).

/**
 * Calculates the great-circle distance between two points, with
 * the Haversine formula.
 * @param float $latitudeFrom Latitude of start point in [deg decimal]
 * @param float $longitudeFrom Longitude of start point in [deg decimal]
 * @param float $latitudeTo Latitude of target point in [deg decimal]
 * @param float $longitudeTo Longitude of target point in [deg decimal]
 * @param float $earthRadius Mean earth radius in [m]
 * @return float Distance between points in [m] (same as earthRadius)
 */
public static function haversineGreatCircleDistance(
  $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
  // convert from degrees to radians
  $latFrom = deg2rad($latitudeFrom);
  $lonFrom = deg2rad($longitudeFrom);
  $latTo = deg2rad($latitudeTo);
  $lonTo = deg2rad($longitudeTo);

  $latDelta = $latTo - $latFrom;
  $lonDelta = $lonTo - $lonFrom;

  $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
  return $angle * $earthRadius;
}

3

Aby sprawdzić, czy lat / lon znajduje się w obrębie lub poza okręgiem ograniczającym, musisz obliczyć odległość od referencyjnego lat / lon do punktu lat / lon, który chcesz przetestować. Ponieważ twoja odległość wynosi 10 km lub mniej, spróbuję użyć przybliżenia Equirectangular, aby uzyskać odległość, a nie Haversine ze względu na prostotę. Aby uzyskać odległość w km:

x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )

Ważna uwaga: lat / lon w tej formule są w radianach, a nie stopniach. Typowa wartość EarthRadius to 6371 km, co zwróci odległość w jednostkach km. Teraz jest to prosty test, czy odległość znajduje się w kręgu, czy poza nim. Jeśli koło ograniczające działa, wybrałbym to.

W przypadku prostokąta ograniczającego przyjmuję, że chcesz zdefiniować prostokąt równolegle do równika. Następnie obliczyłem narożniki obwiedni za pomocą obliczeń zasięgu / łożyska (łożyska to 45 stopni, 135 stopni, 225 stopni i 315 stopni). Stamtąd zakładam, że nie ma cię wokół biegunów i wykorzystaj punkt w teście wielokąta.


2

Poniżej znajduje się kod T-SQL, którego używam do budowania obwiedni w SQL-Server 2012. W moim przypadku otrzymuję wartości dziesiętne dla Lat, Long. Używam tego, aby szybko ograniczyć liczbę wierszy, zanim użyję STDistancefunkcji SQL, aby sprawdzić, czy wyniki rzeczywiście znajdują się w określonej odległości. Funkcje geograficzne są bardzo kosztowne w SQL Server, dlatego budując obwiednię, jestem w stanie znacznie zmniejszyć liczbę operacji, które trzeba wykonać.

DECLARE @Lat DECIMAL(20, 13) = 35.7862
   ,@Long DECIMAL(20, 13) = -80.3095
   ,@Radius DECIMAL(7, 2) = 5
   ,@Distance DECIMAL(10, 2)
   ,@Earth_Radius INT = 6371000;

SET @Distance = @Radius * 1609.344;

DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
   ,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
   ,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
   ,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));

SELECT *
    FROM CustomerPosition AS cp
    WHERE (
            cp.Lat >= @SouthLat
            AND cp.Lat <= @NorthLat )
        AND (
              cp.Long >= @WestLong
              AND cp.Long <= @EastLong )
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.