คำนวณระยะทางเป็นกิโลเมตรไปยังจุดที่ใกล้ที่สุด (กำหนดเป็น lat / long) โดยใช้ ArcGIS DEsktop และ / หรือ R?


10

ฉันมีชุดข้อมูลสองจุดใน ArcGIS ซึ่งทั้งสองชุดจะอยู่ในพิกัด WGS84 lat / lon และจุดกระจายทั่วทั้งโลก ฉันต้องการค้นหาจุดที่ใกล้ที่สุดในชุดข้อมูล A ไปยังจุดแต่ละจุดในชุดข้อมูล B และหาระยะห่างระหว่างจุดเป็นกิโลเมตร

ดูเหมือนว่าจะเป็นการใช้งานเครื่องมือใกล้เคียงอย่างสมบูรณ์แบบ แต่นั่นทำให้ฉันได้ผลลัพธ์ในระบบพิกัดของจุดอินพุต: นั่นคือองศาทศนิยม ฉันรู้ว่าฉันสามารถฉายข้อมูลอีกครั้ง แต่ฉันรวบรวม ( จากคำถามนี้ ) ว่ามันยาก (ถ้าไม่เป็นไปไม่ได้) เพื่อหาเส้นโครงที่จะให้ระยะทางที่แม่นยำทั่วโลก

คำตอบสำหรับคำถามนั้นแนะนำให้ใช้สูตร Haversine เพื่อคำนวณระยะทางโดยใช้พิกัดละติจูด - ลองจิจูดโดยตรง มีวิธีการทำเช่นนี้และได้ผลลัพธ์เป็นกิโลเมตรโดยใช้ ArcGIS หรือไม่? ถ้าไม่เป็นวิธีที่ดีที่สุดในการเข้าถึงนี้คืออะไร?

คำตอบ:


6

แม้ว่านี่ไม่ใช่วิธีแก้ปัญหา ArcGIS แต่ปัญหาของคุณสามารถแก้ไขได้ใน R โดยส่งออกคะแนนของคุณจาก Arc และใช้spDists ฟังก์ชันจากspแพ็คเกจ ฟังก์ชั่นพบว่าระยะทางระหว่างจุดอ้างอิง (s) 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

ไม่จำเป็นต้องวนซ้ำคุณสามารถให้ฟังก์ชั่นสองชุดของคะแนนและมันจะกลับเมทริกซ์ด้วยระยะทางระหว่างแต่ละจุดรวมกัน คำตอบที่แก้ไขเพื่อรวมรหัสตัวอย่าง
อัลเลน

3

มันไม่ใช่โซลูชัน ArcGIS แต่การใช้แบบจำลองข้อมูล Earth Round ในฐานข้อมูลเชิงพื้นที่จะทำเคล็ดลับ การคำนวณระยะทางโลกในฐานข้อมูลที่สนับสนุนนี้จะค่อนข้างง่าย ฉันสามารถแนะนำให้คุณอ่านสอง:

http://postgis.net/workshops/postgis-intro/geography.html

http://blog.safe.com/2012/08/round-earth-data-in-oracle-postgis-and-sql-server/


2

คุณต้องคำนวณระยะทางที่ทำงานกับ Lat / Long Vincentyเป็นสิ่งที่ฉันต้องการใช้ (ความแม่นยำ 0.5 มม.) ฉันเคยเล่นกับมันมาก่อนและมันก็ไม่ยากที่จะใช้

รหัสยาวไปหน่อย แต่ใช้งานได้ เมื่อกำหนดสองจุดใน WGS มันจะคืนค่าระยะทางเป็นเมตร

คุณสามารถใช้สิ่งนี้เป็นสคริปต์ Python ใน ArcGIS หรือล้อมรอบสคริปต์อื่นที่วนซ้ำสอง Point Shapefiles และสร้างเมทริกซ์ระยะทางให้คุณ หรืออาจป้อนผลลัพธ์ของ GENERATE_NEAR_TABLE ได้ง่ายกว่าด้วยการค้นหาคุณลักษณะที่ใกล้ที่สุด 2-3 แห่ง (เพื่อหลีกเลี่ยงภาวะแทรกซ้อนของความโค้งของโลก)

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/th/arcgisdesktop/10.0/help/index.html#//… ) "ระยะทางอยู่ในหน่วยเชิงเส้นของระบบพิกัดคุณลักษณะอินพุต" ซึ่งเป็นคุณลักษณะอินพุตของฉัน ใน lat / lon จะให้ผลลัพธ์เป็นทศนิยมทศนิยมหรือไม่ (ฉันไม่ได้มีเครื่องกับ ArcGIS ที่นี่เพื่อทดสอบ)
robintw

ในกรณีนี้ฉันอาจจะใช้วิธีการแก้ปัญหา "รวดเร็วและสกปรก" โดยการเพิ่มเขตข้อมูล X และ Y ใน datatable ของคุณและคลิกที่คำนวณเรขาคณิตเลือก X และ Y ในหน่วยเมตร หากไม่สามารถเลือกตัวเลือกนี้ได้ให้เปลี่ยนระบบพิกัดของ MXD ของคุณ ก่อนหน้านี้ฉันเคยทำงานในโครงการซึ่งลูกค้าของฉันต้องการค่า R / H แบบยาว / lat และ X / Y และ Gauss-Krueger R / H ทั้งหมดในไฟล์ Shape แต่ละไฟล์ เพื่อหลีกเลี่ยงการคำนวณที่ซับซ้อนเพียงแค่เปลี่ยนการฉายภาพและคำนวณรูปทรงเรขาคณิตเป็นวิธีที่ง่ายที่สุดในการคำนวณ
basto

0

หากคุณต้องการการตรวจวัดทางธรณีวิทยาที่มีความแม่นยำสูงและมีประสิทธิภาพให้ใช้GeographicLibซึ่งเขียนด้วยภาษาโปรแกรมหลายภาษาเช่น C ++, Java, MATLAB, Python เป็นต้น

ดูCFF Karney (2013) "อัลกอริทึมสำหรับธรณีวิทยา"สำหรับการอ้างอิงวรรณกรรม โปรดทราบว่าอัลกอริธึมเหล่านี้มีความแข็งแกร่งและแม่นยำกว่าอัลกอริธึมของ Vincenty ตัวอย่างเช่นใกล้กับแอนตีรหัส

ระยะทางคำนวณเป็นเมตรระหว่างจุดสองจุดรับs12แอตทริบิวต์ระยะทางจากการแก้ปัญหาเนื้อที่ผกผัน เช่นกับแพ็คเกจทางภูมิศาสตร์สำหรับ 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}

หรือทำให้ฟังก์ชั่นอำนวยความสะดวกซึ่งยังแปลงจากเมตรเป็นกิโลเมตร:

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

22.481 กม. ระหว่าง (84.57916462672875, 158.67545706102192) และ (84.70326937581333, 156.9784597422855)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.