C#でメートルを小数に変換する必要があります。私は ウィキペディア を読みました。小数点以下1桁は111.32kmに相当します。しかし、それは赤道上にあるので、私がその上/下にいる場合、私の変換は間違っていますか?私はこれが間違っていると思います:
long sRad = (long.Parse(sRadTBx.Text)) / (111.32*1000);
編集:近くのユーザーを見つけるにはこの検索範囲が必要です
long myLatitude = 100;
long myLongitude = 100;
long sRad = /* right formula to convert meters to decimal degrees*/
long begLat = myLatitude - searchRad;
long endLat = myLatitude + searchRad;
long begLong = myLongitude - searchRad;
long endLong = myLongitude + searchRad;
List<User> FoundUsers = new List<User>();
foreach (User user in db.Users)
{
// Check if the user in the database is within range
if (user.usrLat >= begLat && user.usrLat <= endLat && user.usrLong >= begLong && user.usrLong <= endLong)
{
// Add the user to the FoundUsers list
FoundUsers.Add(user);
}
}
クリストファーオルソンはすでに良い答えを持っていますが、私は理論のいくつかも記入したいと思いました。
私はいつも このウェブページ これらの数式に役立つことを発見しました。
概念に関する簡単なメモ
進行中の実際のジオメトリについて考えてください。
現状では、現在、入力をスケーリングする以外に何もしていません。風船の典型的な例を想像してみてください。バルーンの下部と上部で交わる2本の線を引きます。これらは「上下」に移動するため、経度の線を表します。もちろん、そのような概念は本当にないので、引用しますが、想像することができます。ここで、各線を見ると、長さを上下するにつれて距離が変化することがわかります。元の仕様によると、それらは気球の上部と下部で交わりますが、他の場所では交わりません。同じことが経度の線にも当てはまります。非ユークリッド幾何学は、線が交差する場合、線が正確に2回交差することを示しています。これは、概念化するのが難しい場合があります。しかし、そのため、線の間の距離は赤道全体に効果的に反映されます。
ご覧のとおり、緯度は縦線間の距離に大きく影響します。それらは、北極と南極で最も近いものから、赤道で最も遠いものまでさまざまです。
緯度線は少し簡単です。それらは収束しません。理論上の気球を真っ直ぐ上下に持ち、極を真上と真下に向けると、緯度の線は床に平行になります。より一般的な意味では、それらは縦線の極によって作られる軸(ユークリッドの概念)に垂直になります。したがって、経度に関係なく、距離は緯度間で一定です。
あなたの実装
現在、実装は、これらの線が常に一定の距離にあるという考えに依存しています。その場合は、あなたが持っているように、単純なスケーリングアプローチをとることができるでしょう。実際、それらがユークリッドの意味で平行である場合、時速マイルから時速キロメートルに変換するという概念とそれほど異ならないでしょう。ただし、距離の違いにより、これははるかに複雑になります。
北極の経度間の距離はゼロであり、赤道では、引用したWikipediaページに記載されているように、111.32キロメートルです。したがって、真に正確な結果を得るには、探している緯度を考慮する必要があります。これがもう少し複雑になる理由です。
現実的な結果を得る
さて、あなたが最近編集したことを考えると、あなたが望む式は、あなたがあなたの評価に緯度と経度の両方を取り入れようとしているようです。コード例を考えると、2つの座標間の距離を見つけたいと考えており、短い距離でもうまく機能させたいと考えているようです。したがって、この投稿の冒頭で指摘したWebサイトが示唆しているように、Haversineの公式を提案します。そのウェブサイトはそれに関する多くの良い情報を提供します、しかしこれは公式自体です。愚かなタイプミスをしないように、サイトや記号などから直接コピーしています。したがって、これはもちろんJavaScriptですが、基本的にいくつかのケースを変更するだけで、C#で実行されます。
ここで、φは緯度、λは経度、θは方位(ラジアン、北から時計回り)、δはangular距離(ラジアン)d/R; dは距離です移動した、R地球の半径
var R = 6371; // km
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
ここで注意しなければならないのは、最初の行で宣言されているR
が地球の半径だけだと思います。コメントが示すように、私たちはすでにキロメートル単位で作業しているので、実装のためにそれを変更する必要がある場合とない場合があります。幸いなことに、オンラインで検索して、お気に入りのユニットの地球の(平均)半径を見つけるのは簡単です。
もちろん、toRadians
は単に入力にMath.PI
を掛け、次に180で割ったものであることに注意してください。十分に単純です。
代替
これは本当にあなたのケースに関連しているようには見えませんが、私はそれを含めます。前述の式は正確な結果をもたらしますが、速度が犠牲になります。明らかに、それは個々のレコードではかなり小さな取引ですが、ますます処理するように構築するにつれて、これが問題になる可能性があります。もしそうなら、そしてあなたがかなり集中化された場所で扱っているなら、あなたは私たちの惑星の広大な性質を取り除き、緯度と経度の間の距離に適した数を見つけ、そして惑星を「多かれ少なかれ」として扱うことができますEuclidean」(つまり、フラット)であり、ピタゴラスの定理を使用して値を計算します。もちろん、元のテストサイトから離れるほど、精度は低下します(個人的には、Google Earthまたは同様の製品に問い合わせて、これらの数値を見つけるだけです)。しかし、ユーザーの密集したクラスターを扱っている場合、それはMath
クラスに一連の数式を実行するよりもはるかに高速ですwayいい結果になる。
別のより抽象的な代替案
また、このロジックをどこで行っているかについても考えてみてください。ここで少し足を踏み外し始めますが、SQL Serverにデータを保存している場合は、距離の計算を処理する非常に優れた地理機能がすでに組み込まれています。 GEOGRAPHY
タイプを確認してください。
編集
これはコメントへの応答であり、望ましい結果が実際には境界を示す長方形であることを示唆しています。コードが示唆するように、これは実際には検索の「半径」ではないため、これには反対することをお勧めします。
ただし、その方法に固執したい場合は、緯度用と経度用の2つの別々の距離を確認することになります。これもそのウェブページからです。 φ1
はmyLatitude
であり、λ1
はmyLongitude
です。この式は、方位座標と開始座標を受け入れ、結果の位置を示します。
var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) );
var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
これを使用して、検索長方形の境界を決定できます。
また、同じウィキペディアの記事から:
As one moves away from the equator towards a pole, however,
one degree of longitude is multiplied by
the cosine of the latitude,
decreasing the distance, approaching zero at the pole.
したがって、これは緯度の関数になります。
double GetSRad(double latitude)
{
return 111.32 * Math.Cos(latitude * (Math.PI / 180));
}
または類似。
編集:逆に、メートルを小数度に変換するには、次のようにする必要があります。
double MetersToDecimalDegrees(double meters, double latitude)
{
return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
}