2017-01-30 10 views
1

私は2つの場所のセットがA(20Kの場所)とB(2kの場所)と言います。私は緯度と経度に基づいて、セットAのすべてのロケーションのセットを、セットBの最も近いロケーションにマップしたいと考えています。緯度と経度に基づいて最も近い位置に地図を表示

JavaまたはRには解決策がありますか。 Javaソリューションが優先されます。

+0

私はすべての点についてすべての距離を計算する必要があると思います。私が考えることができる他のすべてのアイデアは、まず距離が必要です... – IQV

+0

これらの位置は、メモリ内でダイナミックにセットAとセットBになっていますか?それとも、データベースの中にそれらを持っているのでしょうか?あなたのアプリが実行されるたびにマップメモリ​​を構築する必要がある場合は、パフォーマンスが非常に良い必要があります。しかし、1回の操作しかできず、マップをどこかに残すことができれば、非常に最適化する必要はありません。それは簡単です。集合Aのすべての場所がBのそれらの場所との最小距離を計算するので、 'O(n * n)'からでしょう – STaefi

+0

プラス誰もあなたのためにそれを書いてくれません。あなた自身でそれを行う必要がありますし、何か問題があれば、助けを得るために[MCVE]を提供する必要があります。 – STaefi

答えて

1

私はコメントに@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 

または、我々はポイントを取るが、マトリックスとして@rosscova

からの回答からも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 
2

内の各点についてpointsBから最も近い点を返し、pointsAからすべてのポイントに適用することができます座標を扱うとき

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楕円体)を使用することを好むことがあります。私は通常に最も近いpointBを取得するには、行を超えるwhich.min関数を適用を使用してSPパッケージから

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

と終わりをspDists機能を使用しますpointA

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

私の解決策よりもはるかに良い、spDistsを使用して素晴らしいアイデア。私は出力よりも有用かもしれない参照ではなく、ポイントを出力するように編集しました。 – rosscova

+0

ありがとう!はい、必要な出力が場所の地図でなければならないので、より便利です。 OPの返事を待ってみましょう! –

+0

'apply(out_Dists、1、which.min)'から返されたベクトルは、MARGIN 1を使って参照するdata.frame 'pointsA'のような長さ3になるので、私は再度答えを編集しました。マージン2はdf点Bへの参照を修正する。 –

0

ここはJavaのものです。緯度と経度を正規化されたベクトル表現に変換することによって数学は単純化され、2つのベクトルが大きいほど、そのドット積は大きくなる(それらが等しいときに近づく)。

これは、地球が球形であることを前提としています。 「完璧な」結果が必要な場合は、より近似した座標を変換する必要があります(たとえば、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}; 
    } 
} 
関連する問題