7

この式を使用して、緯度と経度のフィールドが10進形式である(My)SQLデータベースのエントリ間の距離を計算しています。

6371 * ACOS(SIN(RADIANS( %lat1% )) * SIN(RADIANS( %lat2% )) + 
COS(RADIANS( %lat1% )) * COS(RADIANS( %lat2% )) * COS(RADIANS( %lon2% ) - 
RADIANS( %lon1% )))

%lat1%と%lat2%を適切に置き換えると、WHERE句で別のエントリの特定の半径内のエントリを検索できます。ORDERBY句でLIMITと一緒に使用すると、最も近いxエントリなどが検索されます。

私はこれを主に自分自身へのメモとして書いていますが、改善はいつでも歓迎です。:)

注:以下のValerionで説明されているように、これはキロメートル単位で計算されます。メートル、マイルなどを使用するには、6371を適切な代替番号に置き換えます。

4

4 に答える 4

7

三角関数をサポートしないデータベース (SQLite など) では、ピタゴラスの定理を使用できます。

データベースが三角関数をサポートしている場合でも、これはより高速な方法ですが、次の注意事項があります。

  • lat、lngの代わりに(または同様に)x、yグリッドに座標を保存する必要があります。
  • 計算は「平らな地球」を前提としていますが、これは比較的ローカルな検索には問題ありません。

これは、私が取り組んでいるRailsプロジェクトの例です(重要なのは真ん中のSQLです):

class User < ActiveRecord::Base
  ...
  # has integer x & y coordinates
  ...

  # Returns array of {:user => <User>, :distance => <distance>}, sorted by distance (in metres).
  # Distance is rounded to nearest integer.
  # point is a Geo::LatLng.
  # radius is in metres.
  # limit specifies the maximum number of records to return (default 100).
  def self.find_within_radius(point, radius, limit = 100)

    sql = <<-SQL
      select id, lat, lng, (#{point.x} - x) * (#{point.x} - x) + (#{point.y} - y) * (#{point.y} - y) d 
      from users where #{(radius ** 2)} >= d 
      order by d limit #{limit}
    SQL
    
    users = User.find_by_sql(sql)
    users.each {|user| user.d = Math.sqrt(user.d.to_f).round}
    return users
  end
于 2008-09-23T19:53:25.513 に答える
2

これがHaversineの公式だと思うのは正しいですか?

于 2008-09-18T09:18:18.947 に答える
1

私はこれを使ってきましたが、どこで手に入れたのか忘れてしまいました。

SELECT n, SQRT(POW((69.1 * (n.field_geofield_lat - :lat)) , 2 ) + POW((53 * (n.field_geofield_lon - :lon)), 2)) AS distance FROM field_revision_field_geofield n ORDER BY distance ASC
于 2012-07-23T23:06:28.147 に答える
1

私は車両追跡アプリケーションでまったく同じ方法を使用しており、何年も使用しています。それは完全にうまく機能します。いくつかの古いコードを簡単にチェックすると、結果を 6378137 で乗算したことがわかります。これは、メモリがメートルに変換される場合に役立ちますが、非常に長い間触れていません。

SQL 2008には新しい空間データ型があり、この式を知らなくてもこれらの種類の比較が可能であり、興味深いかもしれない空間インデックスも可能だと思いますが、調べていません。

于 2008-09-18T10:27:13.773 に答える