根据纬度和经度将位置映射到最近的位置

时间:2017-01-30 07:46:54

标签: java r distance latitude-longitude

我有两组位置说A(20K位置)和B(2k位置)。我希望根据它们的纬度和经度,将集合A中所有位置的地图设置为集合B中的最近位置。

java或R中是否有任何解决方案 Java解决方案首选。

3 个答案:

答案 0 :(得分:2)

来自@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 ) ))

然后,在处理坐标时,您可能更喜欢使用Great Circle(WGS84椭球)距离而不是欧几里德。我通常使用 sp 包中的 spDists 功能

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

并最后使用应用功能,并在行上使用 which.min 来获取最近的 pointB pointA

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

答案 1 :(得分:1)

我同意@STaefi的评论,在你要求其他人为你编写代码之前,至少要显示一些一点的工作是个好主意。话虽如此,你的问题引起了我的兴趣,足以抓住我几分钟的时间,所以这是myEnterFunction()中的方法。请注意,这只是将距离视为坐标的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

答案 2 :(得分:0)

这是Java中的一个。通过将纬度和经度转换为标准化矢量表示来简化数学运算,并注意到两个矢量越接近它们的点积(当它们相等时接近一个)。

这假设地球是球形的。如果你想要&#34;完美&#34;结果您需要使用更接近的近似值来转换坐标(例如,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};
    }
}