Tính khoảng cách tính bằng km đến các điểm gần nhất (tính theo lat / long) bằng ArcGIS DEsktop và / hoặc R?


10

Tôi có hai bộ dữ liệu điểm trong ArcGIS, cả hai đều được đưa ra trong tọa độ W / 84 lat / lon và các điểm được trải rộng trên toàn thế giới. Tôi muốn tìm điểm gần nhất trong Bộ dữ liệu A đến từng điểm trong Bộ dữ liệu B và nhận khoảng cách giữa chúng theo km.

Điều này có vẻ như là một cách sử dụng hoàn hảo của công cụ Gần, nhưng điều đó mang lại cho tôi kết quả trong hệ thống phối hợp của các điểm đầu vào: đó là độ thập phân. Tôi biết tôi có thể chiếu lại dữ liệu, nhưng tôi thu thập ( từ câu hỏi này ) rằng rất khó (nếu không thể) tìm ra một phép chiếu sẽ cho khoảng cách chính xác trên toàn thế giới.

Các câu trả lời cho câu hỏi đó đề nghị sử dụng công thức Haversine để tính khoảng cách bằng cách sử dụng tọa độ kinh độ vĩ độ trực tiếp. Có cách nào để làm điều này và nhận được kết quả tính bằng km khi sử dụng ArcGIS không? Nếu không, cách tốt nhất để tiếp cận điều này là gì?

Câu trả lời:


6

Mặc dù đây không phải là giải pháp ArcGIS, nhưng vấn đề của bạn có thể được giải quyết trong R bằng cách xuất điểm của bạn từ Arc và sử dụng spDists chức năng từ spgói. Hàm tìm khoảng cách giữa (các) điểm tham chiếu và ma trận điểm, tính bằng km nếu bạn đặt longlat=T.

Đây là một ví dụ nhanh và bẩn:

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)

Cảm ơn - đây có vẻ như là giải pháp thực tế nhất. Nhìn vào các tài liệu có vẻ như tôi chỉ có thể làm điều này giữa một điểm tham chiếu và một tập hợp các điểm khác, vì vậy tôi sẽ phải thực hiện nó trong một vòng lặp để đi qua tất cả các điểm của mình. Bạn có biết một cách hiệu quả hơn để làm điều này trong R?
robintw

Không cần lặp, bạn có thể cung cấp cho hàm hai bộ điểm và nó sẽ trả về một ma trận với khoảng cách giữa mỗi tổ hợp điểm. Chỉnh sửa câu trả lời để bao gồm mã ví dụ.
allen


2

Bạn cần tính toán khoảng cách hoạt động với Lat / Long. Vincenty là cái tôi sẽ sử dụng (độ chính xác 0,5mm). Tôi đã chơi với nó trước đây và nó không quá khó để sử dụng.

Mã này hơi dài, nhưng nó hoạt động. Cho hai điểm trong WGS, nó sẽ trả về một khoảng cách tính bằng mét.

Bạn có thể sử dụng tập lệnh này như một tập lệnh Python trong ArcGIS hoặc bọc nó xung quanh một tập lệnh khác chỉ đơn giản lặp lại qua hai Hình dạng điểm và xây dựng ma trận khoảng cách cho bạn. Hoặc, có thể dễ dàng hơn để cung cấp kết quả của GENERATE_NEAR_TABLE bằng cách tìm 2-3 tính năng gần nhất (để tránh các biến chứng của độ cong của trái đất).

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

Tôi đã tạo ra những trải nghiệm tương tự với các bộ dữ liệu nhỏ bằng công cụ Khoảng cách điểm. Làm như vậy, bạn không thể tự động tìm các điểm gần nhất trong Bộ dữ liệu A của mình, nhưng ít nhất có được kết quả đầu ra của bảng với kết quả km hoặc m hữu ích. Trong bước tiếp theo, bạn có thể chọn khoảng cách ngắn nhất đến từng điểm của Bộ dữ liệu B ra khỏi bảng.

Nhưng phương pháp này sẽ phụ thuộc vào số điểm trong bộ dữ liệu của bạn. Nó có thể không hoạt động đúng với các bộ dữ liệu lớn.


Cám ơn vì sự gợi ý. Tuy nhiên, tôi không thể thấy điều đó sẽ giúp tôi như thế nào. Theo các tài liệu ( help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#// . trong lat / lon chắc chắn sẽ cho tôi kết quả bằng độ thập phân? (Tôi chưa có máy nào có ArcGIS ở đây để kiểm tra)
robintw

Trong trường hợp này, tôi có thể sẽ sử dụng giải pháp "nhanh và bẩn" bằng cách thêm các trường X và Y vào dữ liệu của bạn và nhấp vào Tính toán Hình học chọn X và Y theo mét. Nếu không thể chọn tùy chọn này, hãy thay đổi hệ tọa độ của MXD của bạn. Tôi đã làm việc trên một dự án trước đây, nơi khách hàng của tôi muốn các giá trị R / H dài / lat, X / Y và Gauss-Krueger trong mỗi tệp Shape. Để tránh tính toán phức tạp, chỉ cần thay đổi các hình chiếu và tính toán hình học là cách dễ dàng nhất để thực hiện.
basto

0

Nếu bạn cần các phép đo trắc địa mạnh mẽ và chính xác cao, hãy sử dụng GeographicLib , được viết bằng ngôn ngữ lập trình, bao gồm C ++, Java, MATLAB, Python, v.v.

Xem CFF Karney (2013) "Thuật toán cho trắc địa" để tham khảo văn học. Lưu ý rằng các thuật toán này mạnh hơn và chính xác hơn thuật toán của Vincenty, ví dụ gần các phản hạt.

Để tính khoảng cách tính bằng mét giữa hai điểm, hãy lấy s12thuộc tính khoảng cách từ giải pháp trắc địa nghịch đảo . Ví dụ: với gói geographiclib cho Python

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}

Hoặc thực hiện một chức năng tiện lợi, cũng chuyển đổi từ mét sang km:

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

Bây giờ để tìm điểm gần nhất giữa các danh sách AB, mỗi điểm có 100 điểm:

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

22.481 km giữa (84.57916462672875, 158.67545706102192) và (84,70326937581333, 156.9784597422855)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.