ArcGIS DEsktop 및 / 또는 R?


10

ArcGIS에는 두 개의 점 데이터 세트가 있으며 둘 다 WGS84 위도 / 경도 좌표로 제공되며 점은 전 세계에 퍼져 있습니다. Dataset A의 가장 가까운 점을 Dataset B의 각 점에 대해 찾아서 그 사이의 거리를 킬로미터 단위로 가져오고 싶습니다.

이것은 근거리 도구를 완벽하게 사용하는 것처럼 보이지만 입력 포인트의 좌표 시스템 즉 10 진수를 제공합니다. 나는 데이터를 다시 투영 할 수 있다는 것을 알고 있지만 ( 이 질문에서 ) 전 세계에서 정확한 거리를 줄 수있는 투영법을 찾는 것이 어렵다는 것을 수집 합니다.

이 질문에 대한 답변은 Haversine 공식을 사용하여 위도-경도 좌표를 직접 사용하여 거리를 계산할 것을 제안합니다. ArcGIS를 사용하여이를 수행하고 km를 결과로 얻는 방법이 있습니까? 그렇지 않다면 이것에 접근하는 가장 좋은 방법은 무엇입니까?

답변:


6

이것이 ArcGIS 솔루션은 아니지만 Arc에서 포인트를 내보내고 패키지 의 spDists 함수를 사용하여 R에서 문제를 해결할 수 있습니다 sp. 이 함수는 설정 한 경우 기준점과 점 행렬 사이의 거리를 킬로미터 단위로 찾습니다 longlat=T.

다음은 빠르고 더러운 예입니다.

library(sp)
## Sim up two sets of 100 points, we'll call them set a and set b:
a <- SpatialPoints(coords = data.frame(x = rnorm(100, -87.5), y = rnorm(100, 30)), proj4string=CRS("+proj=longlat +datum=WGS84"))
b <- SpatialPoints(coords = data.frame(x = rnorm(100, -88.5), y = rnorm(100, 30.5)), proj4string=CRS("+proj=longlat +datum=WGS84"))

## Find the distance from each point in a to each point in b, store
##    the results in a matrix.
results <- spDists(a, b, longlat=T)

고마워-이것은 가장 현실적인 솔루션처럼 보입니다. 문서를 보면 참조 지점과 다른 지점 사이에서만이 작업을 수행 할 수있는 것처럼 보이므로 모든 지점을 통과하려면 루프에서 수행해야합니다. R에서 더 효율적인 방법을 알고 있습니까?
robintw

루핑이 필요하지 않으며 함수에 두 개의 점 세트를 제공 할 수 있으며 각 점 조합 사이의 거리를 가진 행렬을 반환합니다. 예제 코드를 포함하도록 편집 된 답변입니다.
allen


2

Lat / Long에서 작동하는 거리 계산이 필요합니다. Vincenty 는 내가 사용하는 것입니다 (정확도 0.5mm). 나는 전에 그것을 가지고 놀았고 사용하기 너무 어렵지 않습니다.

코드는 약간 길지만 작동합니다. WGS에서 두 점이 주어지면 미터 단위의 거리를 반환합니다.

이것을 ArcGIS에서 Python 스크립트로 사용하거나 단순히 두 개의 Point Shapefile을 반복하고 거리 매트릭스를 작성하는 다른 스크립트를 둘러 쌀 수 있습니다. 또는, 지구의 곡률의 합병증을 피하기 위해 2-3 개의 가장 가까운 피처를 찾아 GENERATE_NEAR_TABLE의 결과를 제공하는 것이 더 쉽습니다.

import math

ellipsoids = {
    #name        major(m)   minor(m)            flattening factor
    'WGS-84':   (6378137,   6356752.3142451793, 298.25722356300003),
    'GRS-80':   (6378137,   6356752.3141403561, 298.25722210100002),
    'GRS-67':   (6378160,   6356774.5160907144, 298.24716742700002),

}

def distanceVincenty(lat1, long1, lat2, long2, ellipsoid='WGS-84'):
    """Computes the Vicenty distance (in meters) between two points
    on the earth. Coordinates need to be in decimal degrees.
    """
    # Check if we got numbers
    # Removed to save space
    # Check if we know about the ellipsoid
    # Removed to save space
    major, minor, ffactor = ellipsoids[ellipsoid]
    # Convert degrees to radians
    x1 = math.radians(lat1)
    y1 = math.radians(long1)
    x2 = math.radians(lat2)
    y2 = math.radians(long2)
    # Define our flattening f
    f = 1 / ffactor
    # Find delta X
    deltaX = y2 - y1
    # Calculate U1 and U2
    U1 = math.atan((1 - f) * math.tan(x1))
    U2 = math.atan((1 - f) * math.tan(x2))
    # Calculate the sin and cos of U1 and U2
    sinU1 = math.sin(U1)
    cosU1 = math.cos(U1)
    sinU2 = math.sin(U2)
    cosU2 = math.cos(U2)
    # Set initial value of L
    L = deltaX
    # Set Lambda equal to L
    lmbda = L
    # Iteration limit - when to stop if no convergence
    iterLimit = 100
    while abs(lmbda) > 10e-12 and iterLimit >= 0:
        # Calculate sine and cosine of lmbda
        sin_lmbda = math.sin(lmbda)
        cos_lmbda = math.cos(lmbda)
        # Calculate the sine of sigma
        sin_sigma = math.sqrt(
                (cosU2 * sin_lmbda) ** 2 + 
                (cosU1 * sinU2 - 
                 sinU1 * cosU2 * cos_lmbda) ** 2
        )
        if sin_sigma == 0.0:
            # Concident points - distance is 0
            return 0.0
        # Calculate the cosine of sigma
        cos_sigma = (
                    sinU1 * sinU2 + 
                    cosU1 * cosU2 * cos_lmbda
        )
        # Calculate sigma
        sigma = math.atan2(sin_sigma, cos_sigma)
        # Calculate the sine of alpha
        sin_alpha = (cosU1 * cosU2 * math.sin(lmbda)) / (sin_sigma)
        # Calculate the square cosine of alpha
        cos_alpha_sq = 1 - sin_alpha ** 2
        # Calculate the cosine of 2 sigma
        cos_2sigma = cos_sigma - ((2 * sinU1 * sinU2) / cos_alpha_sq)
        # Identify C
        C = (f / 16.0) * cos_alpha_sq * (4.0 + f * (4.0 - 3 * cos_alpha_sq))
        # Recalculate lmbda now
        lmbda = L + ((1.0 - C) * f * sin_alpha * (sigma + C * sin_sigma * (cos_2sigma + C * cos_sigma * (-1.0 + 2 * cos_2sigma ** 2)))) 
        # If lambda is greater than pi, there is no solution
        if (abs(lmbda) > math.pi):
            raise ValueError("No solution can be found.")
        iterLimit -= 1
    if iterLimit == 0 and lmbda > 10e-12:
        raise ValueError("Solution could not converge.")
    # Since we converged, now we can calculate distance
    # Calculate u squared
    u_sq = cos_alpha_sq * ((major ** 2 - minor ** 2) / (minor ** 2))
    # Calculate A
    A = 1 + (u_sq / 16384.0) * (4096.0 + u_sq * (-768.0 + u_sq * (320.0 - 175.0 * u_sq)))
    # Calculate B
    B = (u_sq / 1024.0) * (256.0 + u_sq * (-128.0 + u_sq * (74.0 - 47.0 * u_sq)))
    # Calculate delta sigma
    deltaSigma = B * sin_sigma * (cos_2sigma + 0.25 * B * (cos_sigma * (-1.0 + 2.0 * cos_2sigma ** 2) - 1.0/6.0 * B * cos_2sigma * (-3.0 + 4.0 * sin_sigma ** 2) * (-3.0 + 4.0 * cos_2sigma ** 2)))
    # Calculate s, the distance
    s = minor * A * (sigma - deltaSigma)
    # Return the distance
    return s

1

Point Distance 도구를 사용하여 작은 데이터 세트와 비슷한 경험을했습니다. 그렇게하면 데이터 세트 A에서 가장 가까운 점을 자동으로 찾을 수 없지만 최소한 유용한 km 또는 m 결과가있는 테이블 출력을 얻습니다. 다음 단계에서는 테이블에서 데이터 세트 B의 각 지점까지의 최단 거리를 선택할 수 있습니다.

그러나이 방법은 데이터 세트의 포인트 수에 따라 다릅니다. 큰 데이터 세트에서는 제대로 작동하지 않을 수 있습니다.


제안 해 주셔서 감사합니다. 그러나 그것이 어떻게 도움이되는지 볼 수 없습니다. 문서 ( help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//… ) 에 따르면 "거리는 입력 피처 좌표계의 선형 단위입니다." 위도 / 경도로는 반드시 10 진수로 결과를 제공합니까? (테스트 할 ArcGIS가있는 머신은 없습니다)
robintw

이 경우 데이터 테이블에 X 및 Y 필드를 추가하여 "빠르고 더러운"솔루션을 사용하고 미터 단위로 X 및 Y를 선택하는 계산 기하학을 클릭합니다. 이 옵션을 선택할 수 없으면 MXD의 좌표계를 변경하십시오. 클라이언트가 각 Shape 파일에서 long / lat, X / Y 및 Gauss-Krueger R / H 값을 모두 원했던 이전의 프로젝트를 진행하고있었습니다. 복잡한 계산을 피하려면 투영을 변경하고 지오메트리를 계산하는 것이 가장 쉬운 방법이었습니다.
basto

0

고정밀하고 강력한 측지 측정이 필요한 경우 C ++, Java, MATLAB, Python 등을 비롯한 여러 프로그래밍 언어로 작성된 GeographicLib를 사용하십시오 .

참조 CFF Karney (2013) "측지선을위한 알고리즘" 문학 참조. 이러한 알고리즘은 Vincenty 알고리즘보다 강력하고 정확합니다 (예 : antipodes).

두 점 사이의 거리를 미터 단위로 계산하려면 역 측지 솔루션s12 에서 거리 속성을 가져옵니다 . 예를 들어, 파이썬 용 geographiclib 패키지

from geographiclib.geodesic import Geodesic
g = Geodesic.WGS84.Inverse(-41.32, 174.81, 40.96, -5.50)
print(g)  # shows:
{'a12': 179.6197069334283,
 'azi1': 161.06766998615873,
 'azi2': 18.825195123248484,
 'lat1': -41.32,
 'lat2': 40.96,
 'lon1': 174.81,
 'lon2': -5.5,
 's12': 19959679.26735382}

또는 미터에서 킬로미터로 변환하는 편리한 기능을 만드십시오.

dist_km = lambda a, b: Geodesic.WGS84.Inverse(a[0], a[1], b[0], b[1])['s12'] / 1000.0
a = (-41.32, 174.81)
b = (40.96, -5.50)
print(dist_km(a, b))  # 19959.6792674 km

이제 목록 사이의 가장 가까운 지점 찾기 위해 A하고 B, 100 점으로 각각 :

from random import uniform
from itertools import product
A = [(uniform(-90, 90), uniform(-180, 180)) for x in range(100)]
B = [(uniform(-90, 90), uniform(-180, 180)) for x in range(100)]
a_min = b_min = min_dist = None
for a, b in product(A, B):
    d = dist_km(a, b)
    if min_dist is None or d < min_dist:
        min_dist = d
        a_min = a
        b_min = b

print('%.3f km between %s and %s' % (min_dist, a_min, b_min))

(84.57916462672875, 158.67545706102192)와 (84.70326937581333, 156.9784597422855) 사이 22.481km

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