주어진 거리와 위도 / 경도에 대한 경계 상자를 계산하는 방법


13

주어진 WGS84 위도 및 WGS84 경도 및 거리에 대한 경계 상자 또는 원을 계산할 수 있어야하지만 어디서부터 시작해야할지 모르겠습니다!

Lat / Lon 시작부터의 거리는 10Km 이하입니다.

누군가 나에게 몇 가지 포인터를 줄 수 있습니까?


극을 가리지 않는 원의 경우 gis.stackexchange.com/questions/19221/…에 자세한 답변이 제공됩니다 . 그러나 현재 답변에서 알 수 있듯이 이것은 속도 정확도 프로그램 복잡성을 절충 할 수 있습니다. 위도-경로에서 작업 할 때 바운딩 박스를 지정하는 데 "랩 어라운드"문제가 있습니다 (어려움은 + -180도 자오선에서 발생 함). 이에 대한 해결책은 gis.stackexchange.com/questions/17788/…를 참조하십시오 .
whuber

당신은 정말로 상자가 필요합니까, 아니면 주어진 점 근처의 4 점이면 충분합니까? 점 p가 주어진 경우, p에서 NE, SW, SE 및 NW 방향으로 4 개의 거리 d를 찾습니다.
Kirk Kuykendall

@Kirk-4 포인트의 좌표가 있다면 상자가 있습니다.
martinstoeckli

@ martinstoeckli 맞습니다. 구에 투영 된 상자가 어떻게 보이는지 시각화하지 않아도 문제를 단순화하기를 바랐습니다. 상자의 측면이 동일한 위도 / 경도 (즉, 회전 된 상자)에서 떨어지지 않아도되도록 문제를 일반화 할 수도 있습니다.
Kirk Kuykendall

@ Kirk-Ahh 글쎄, 당신이 그것을 정확하게 필요로한다면, 물론 당신은 맞습니다. 이 상자는 가능한 후보자를 빨리 찾는 데 유용하다고 생각합니다. 두 지점이 일정 거리 (원) 내에 있는지 확인하기 위해 더 복잡한 헤르 세인 공식을 사용할 수 있습니다.
martinstoeckli

답변:


15

무슨 WGS? WGS-84? 필요한 정확도에 따라 더 많은 정보를 알아야 할 수도 있습니다. 내 생각에 당신이 투표권을 잃은 이유는 아무도 없습니다.

두 가지 방법이 있습니다.

부정확하지만 아마도 '충분히 좋을 것'

위도 1 도는 WGS-84 데이텀을 사용하여 약 10001.965729 / 90 킬로미터 (적도에서 극까지의 거리, 90 도로 나눔) 또는 111.113km입니다. 이것은 지구의 모양으로 인한 근사치이며 극에 접근함에 따라 거리가 변하기 때문에 (경도가 아닌 위도를 사용해야하는 한 가지 이유-경도의 1도 거리는 0입니다!) 지구도 완벽하지 않습니다 구체. 이 두 가지 이유는 두 번째 대답에서 더 복잡한 투영 및 데이텀 기반 접근 방식을 사용하는 이유입니다.

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

이것은도 / 분 / 초가 아닌 십진도를 사용합니다.

따라서 경계 상자 가 포인트, 플러스 마이너스 0.08999 도가됩니다. 또는이 숫자를 반경으로 사용하여 경계 원을 제공 할 수 있습니다 .

이것을 읽는 모든 GIS 사람은 떨립니다. 그러나 세계 어느 곳에 있는지에 따라 대부분 정확합니다. 반경 10km의 경우 괜찮습니다.

훨씬 더 정확하지만 더 많은 코드

프로젝션 라이브러리를 사용하고 데이텀 등을 지정하십시오. Proj4를 추천합니다. 널리 사용되므로 Google은 이에 대한 질문에 대해 많은 결과를 반환하며 Delphi 래퍼가 있습니다. 사용에 문제가 있으면 여기에 다른 질문을 게시하십시오.이 질문의 범위를 벗어났습니다. Proj4 웹 사이트에는 기본 API를 사용하는 예제가 있으며, C로되어 있지만 상당히 쉽게 번역 할 수 있어야합니다. 이들의 API 레퍼런스 에 의해 다음에 시작하는 가장 좋은 장소이며, 자주 묻는 질문 .

사용하려는 특정 좌표를 알지 못하거나 좌표를 만드는 데 사용 된 경우를 제외하고 WGS-84를 기본 데이텀 (지구 표현)으로 사용합니다. 일반적으로 사용되며 매우 정확합니다.

위치가 Google지도에서 온 경우 (예 : Mercator 투영)를 지정하십시오. 다른 투영법을 사용하거나 UTM 좌표 를 사용할 수 있습니다데이터 소스에 따라 작은 지역에 대해 높은 정확도를 원하는 경우 위도 및 경도 대신 (UTM에는 여러 영역이 있으며, 그 영역 내에서 왜곡을 변경하여 매우 정확합니다. 영역 외부의 좌표에 영역을 사용하면 멀리 이동할 때 왜곡이 크게 증가합니다. 영역 내에서는 인식 할 수 없을 수 있지만, 영역 내에서 UTM 번역은 가능한 한 우수 할 것입니다. 좌표는 일반적으로 각도가 아닌 미터 단위로 지정되므로 10km가 필요할 경우 더 유용 할 수 있습니다 반경 10km는 단일 구역 내에서 쉽게 구할 수 있으므로 중심 좌표를 기준으로 적절한 구역을 선택하기 만하면됩니다. 가장 까다로운 부분은 국경에 접근 할 때뿐입니다. 일반적인 상황이며 괜찮습니다.어떤 것을 사용하는지 선택하는 데 일관 적입니다 . 또한 Proj4를 사용하면 투영을 변환 할 수 있으므로 메르카토르 WGS-84 위도 / 경도에서 UTM 영역 n으로 또는 두 개의 UTM 영역으로 이동할 수 있습니다.)


2
우리가 사는 곳에서 한 측량 관은 자신의 정신 계산에 대략 108km에 해당하는 1도를 사용한다고 말했습니다. 정신적으로 10km는 대략 0.1 도입니다. 이는 대략적인 근사치이므로 정확도 수준을 의미하므로 0.089982311915998이 아닌 1 개의 유효 자릿수 (최대 2 또는 3)로 정확하게 처리하는 것이 가장 좋습니다.
Stephen Quan

1
위도를 고려하여 더 정확한 각도를 계산하는 것은 어렵지 않습니다. 컴퓨터가 계산을 수행하기 때문에 근사치로 얻은 것은 없습니다 (내 예제의 첫 번째 기능 참조).
martinstoeckli

3

데이터베이스에서 쿼리를하고 싶다고 가정하면, 빠른 (정확하지 않은) 검색을 수행 한 후 결과 장소의 거리를 정확하게 계산할 수 있습니다. 당신의 시나리오입니까?

다음 함수 (PHP에서 죄송합니다)는 위도와 경도의 차이를 대략적으로 계산합니다. 이 차이는 검색 지점의 위도에 따라 다릅니다. 데이터베이스에서 빠른 검색을하려면 작은 공차를 사용하십시오. 상자는 위도 + 델타 위도 및 경도 + 델타 경도로 간단히 계산할 수 있습니다.

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

하버 사인 공식 , 당신은 구체 거리를 계산할 수 있습니다. "정확한"거리를 얻으려면 찾은 각 장소에 사용하십시오. 이렇게하면 두 장소가 특정 반경 (상자 대신 원) 내에있는 경우 테스트 할 수 있습니다.

/**
 * 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

위도 / 경도가 경계 원 내부 또는 외부에 있는지 테스트하려면 참조 위도 / 경도에서 테스트하려는 위도 / 경도까지의 거리를 계산해야합니다. 귀하의 거리가 10km 이하이므로 간단 함 때문에 Haquireine 대신 거리를 얻기 위해 Equirectangular 근사법을 사용하려고합니다. 거리를 킬로미터 단위로 얻으려면 :

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

중요 사항 :이 공식에서 위도 / 경도는 각도가 아닌 라디안입니다. EarthRadius의 일반적인 값은 6371km이며 거리를 킬로미터 단위로 반환합니다. 이제 거리가 원 안에 있거나 바깥에 있는지 간단한 테스트입니다. 경계 원이 작동하면 그와 함께 갈 것입니다.

경계 사각형의 경우 적도와 평행하게 정의 된 사각형을 원한다고 가정합니다. 그런 다음 범위 / 베어링 계산을 사용하여 경계 상자의 모서리를 계산합니다 (베어링은 45도, 135도, 225도 및 315도). 거기에서, 나는 당신이 극 주위에 있지 않다고 가정하고 다각형 테스트에서 점을 사용합니다.


2

다음은 SQL-Server 2012에서 경계 상자를 작성하는 데 사용하는 T-SQL 코드입니다. 필자의 경우 Lat, Long에 대한 10 진수 값을 얻습니다. SQL STDistance함수를 사용하여 결과가 실제로 특정 거리 내에 있는지 확인 하기 전에 이것을 사용하여 행 수를 빠르게 제한 합니다. 지리 함수는 SQL Server에서 매우 비용이 많이 들기 때문에 경계 상자를 작성하여 실행 횟수를 크게 줄일 수 있습니다.

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 )
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.