簡體   English   中英

根據緯度和經度將位置映射到最近的位置

[英]Map locations to their nearest location based on latitude and longitude

我有兩組位置,分別是A(2萬個位置)和B(2k個位置)。 我想根據位置的經度和緯度,將A組中所有位置都映射到B組中最接近的位置。

有Java或R中的任何解決方案嗎?首選Java解決方案。

從@rosscova的答案

拿點,但作為矩陣

pointsA <- as.matrix(data.frame( lat = c( 10, 12, 20 ), lon = c( 12, 17, 10 ) ))
pointsB <- as.matrix(data.frame( lat = c( 11, 15 ), lon = c( 15, 15 ) ))

然后,在處理坐標時,您可能更喜歡使用大圓(WGS84橢球)距離而不是歐幾里得距離。 我通常使用sp包中的spDists函數

library( sp )
out_Dists <- spDists(x = pointsA, y = pointsB, longlat = TRUE, segments = FALSE, diagonal = FALSE)

在使用與which.min超過行的應用功能以最終獲得最近pointB點A

pointsA[ apply(out_Dists, 1, which.min), ]

我@STaefi同意的意見,這是一個好主意,要求別人寫的代碼在你面前表現出至少您的部分工作一點點 話雖如此,您的問題引起了我的興趣,足以吸引我幾分鍾的時間,因此這是R的一種方法。 請注意,盡管這只是將距離視為坐標的sqrt(a^2+b^2)函數,但除赤道外其他任何地方都不准確。 如果需要更高的准確性,則需要對其進行修改。

取一個小的假設數據集:

pointsA <- data.frame( lat = c( 10, 12, 20 ), lon = c( 12, 17, 10 ) )
pointsB <- data.frame( lat = c( 11, 15 ), lon = c( 15, 15 ) )

編寫一個用於計算最接近點的函數:

closest_point <- function( lat1, lon1, lat2, lon2 ) {
    x_dist <- abs( lon1 - lon2 )
    y_dist <- abs( lat1 - lat2 )
    dist <- sqrt( x_dist ^ 2 + y_dist ^ 2 )
    closest <- data.frame( lat = lat2[ which.min( dist ) ],
                           lon = lon2[ which.min( dist ) ] )
    return( closest )
}

我們可以從一個點執行該功能pointsA ,返回從最近點pointsB

closest_point( pointsA[1,"lat"], pointsA[1,"lon"], pointsB[,"lat"], pointsB[,"lon"] )
#   lat lon
# 1  11  15

或者,我們可以將其應用到從所有點pointsA ,返回從最近點pointsB對每個點的pointsA

closest.points <- lapply( seq_len( nrow( pointsA ) ),
                          function(x) {
                              closest_point( lat1 = pointsA[x,"lat"],
                                             lon1 = pointsA[x,"lon"],
                                             lat2 = pointsB[,"lat"],
                                             lon2 = pointsB[,"lon"] )
                          } )
closest.points <- do.call( rbind, closest.points )
closest.points
#   lat lon
# 1  11  15
# 2  11  15
# 3  15  15

這是Java中的一個。 通過將緯度和經度轉換為歸一化的向量表示形式,簡化了數學運算,並注意到兩個向量越接近,其點積就越大(當它們相等時,接近一個)。

假設地球是球形的。 如果要獲得“完美”的結果,則需要使用更接近的近似值(例如WGS84)轉換坐標。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.lang.Math.*;

public class LatLong {
    public static void main(String[] args) throws Exception {
        // A random lat/long
        double[] target = randLatLong();
        // Transform to ECEF vector
        double[] targetv = toEcef(target);
        // 2000 random candidates
        List<double[]> b = Stream.generate(LatLong::randLatLong).limit(2000).collect(Collectors.toList());
        // Transform candidates to ECEF representation
        List<double[]> bv = b.stream().map(LatLong::toEcef).collect(Collectors.toList());

        // Find the closest candidate to the target
        int i = closest(targetv, bv);

        System.out.println("Closest point to " + target[0] + ", " + target[1] + " is " + b.get(i)[0] + ", " + b.get(i)[1]);
    }

    // index of closest vector to target from list of candidates
    public static int closest(double[] target, List<double[]> candidates) {
        double p = Double.MIN_VALUE;
        int closest = -1;
        for (int i = 0; i < candidates.size(); i++) {
            double next = dotProduct(target, candidates.get(i));
            if (next > p) {
                p = next;
                closest = i;
            }
        }
        return closest;
    }

    // dot product of two 3vectors
    public static double dotProduct(double[] v1, double[] v2) {
        return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
    }

    // lat/long in degrees to normalised ECEF vector
    public static double[] toEcef(double[] latLong) {
        return toEcef(toRadians(latLong[0]), toRadians(latLong[1]));
    }

    // lat/long in radians to normalised ECEF vector
    public static double[] toEcef(double φ, double λ) {
        return new double[] {cos(φ) * cos(λ), cos(φ) * sin(λ), sin(φ)};
    }

    // A random lat/long
    public static double[] randLatLong() {
        return new double[] {Math.random() * 180 - 90, Math.random() * 360 - 180};
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM