12

これは明確ではないかもしれません。私が基地から外れている場合、またはより多くの情報が必要な場合は、コメントを残してください。おそらく、私が PHP で求めているものに対する解決策が既に存在します。

経度または緯度の値から距離を加算または減算する関数を探しています。

理由: すべての緯度と経度を含むデータベースがあり、X キロメートル (またはマイル) 以内のすべての都市を抽出するクエリを作成したいと考えています。私のクエリは次のようになります...

Select * From Cities Where (Longitude > X1 and Longitude < X2) And (Latitude > Y1 and Latitude < Y2)

 Where X1 = Longitude - (distance)
 Where X2 = Longitude + (distance)

 Where Y1 = Latitude - (distance)
 Where Y2 = Latitude + (distance)

私はMySqlデータベースを使用してPHPで作業しています。

どんな提案も受け付けています!:)

4

10 に答える 10

17

これはまさにあなたが望むことを行う MySQL クエリです。地球は完全な球形ではなく、山、丘、谷などを考慮していないため、このようなものは一般的に概算であることに注意してください.AcademicHomes.comでPHPとMySQLを使用してこのコードを使用すると、$内のレコードが返されます$latitude、$longitude の半径マイル。

$res = mysql_query("SELECT
    * 
FROM
    your_table
WHERE
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) ASC");
于 2009-05-01T13:18:36.387 に答える
3

編集: どこかに、世界のすべての都市とその緯度のリストがある場合。そして長い。値、ルックアップを行うことができます。この場合、緯度で経度 1 度の幅を計算する式については、以下の最初のリンクを参照してください代替テキスト

代替テキスト

正直なところ、この問題の背後にある複雑さは、Google マップなどのサービスを使用してデータを取得する方がはるかに優れているということです。具体的には、地球は完全な球体ではなく、赤道に近づく/遠ざかるにつれて 2 度間の距離が変化します。

私が言いたいことの例についてはhttp://en.wikipedia.org/wiki/Geographic_coordinate_systemを参照し、Google Maps APIをチェックしてください。

于 2009-04-30T21:07:42.960 に答える
1

含める都市の数に応じて、リストを事前に計算できます。ここでは、+100m の不正確さがセットアップには大きすぎる内部アプリケーションのためにこれを行います。これは、location1、location2、distance の 2 つのキー テーブルを持つことで機能します。次に、location1 から location x の距離を非常に迅速に引き戻すことができます。

また、計算はオフラインで実行できるため、システムの実行には影響しません。また、ユーザーはより迅速に結果を得ることができます。

于 2009-05-01T08:47:54.587 に答える
1

上記のコードを使用してみましたが、ポイント間の距離が 20 ~ 30 マイルの範囲にある場合、答えが大きくずれていました。数マイルの誤差があっても問題ありません。私のマッピング仲間と話し、代わりにこれを思いつきました. コードは python ですが、かなり簡単に翻訳できます。ラジアンへの一定の変換を避けるために、データベースを再編集し、緯度/経度のポイントを度からラジアンに変換しました。これの良いところは、計算の大部分がほとんど 1 回で済むことです。

ra = 3963.1906 # radius @ equator in miles, change to km  if you want distance in km
rb = 3949.90275  # radius @ poles in miles, change to km  if you want distance in km
ra2 = ra * ra
rb2 = rb * rb

phi = self.lat

big_ol_constant = (math.pow(ra2*math.cos(phi), 2) + pow(rb2*math.sin(phi), 2))/ (pow(ra*math.cos(phi), 2) + pow(rb*math.sin(phi), 2))

sqlWhere = "%(distance)g > sqrt((power(lat - %(lat)g,2) + power(lng-%(lng)g,2)) * %(big_ol_constant)g)" % {
    'big_ol_constant': big_ol_constant, 'lat': self.lat, 'lng': self.lng, 'distance': distance}

# This is the Django portion of it, where the ORM kicks in.  sqlWhere is what you would put after the WHERE part of your SQL Query.
qs = ZipData.objects.extra(where=[sqlWhere]);

離れた距離が小さい場合は非常に正確であるように思われ、距離が 200 マイルになると 10 マイル程度以内になります (もちろん、それまでには、「カラスが飛ぶように」対「舗装された道路」で問題が発生します)。

これが、上で言及したモデル ZipData です。

class ZipData(models.Model):
    zipcode = ZipCodeField(null=False, blank=False, verbose_name="ZipCode", primary_key=True)
    city = models.CharField(max_length=32, null=False, blank=False)
    state = models.CharField(max_length=2)
    lat = models.FloatField(null=False, blank=False)
    lng = models.FloatField(null=False, blank=False)

追加の注意として、GeoNames.orgで郵便番号に関連する多数の地理データを取得でき、同様に使用できる Web サービス API もいくつか用意されています。

于 2010-06-07T14:30:36.897 に答える
0

たくさんあります(悪いオプション)

  • 数式 (X1-X2 と Y1-Y2 を扱う) をベクトルとして距離を計算します。

  • すべての組み合わせで事前にルックアップ テーブルを作成し、距離を保ちます。

  • MySQL の GIS 固有の拡張機能の使用を検討してください。これについて私が見つけた1つの記事があります。

于 2009-04-30T20:48:35.190 に答える
0

以下の関数は、nerddinnerの ( codeplex で入手可能なASP.NET MVC サンプル アプリケーション) データベース (MSSQL) からのものです。

ALTER FUNCTION [dbo].[DistanceBetween] (@Lat1 as real,
                @Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
                 * COS (@dLat2InRad)
                 * SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END

これが役立つと思います。

于 2009-04-30T21:30:29.660 に答える
0

車輪を再発明しないでください。これは空間クエリです。MySQL の組み込みの空間拡張機能を使用して、緯度経度の座標データをネイティブの MySQL ジオメトリ列タイプに格納します。次に、Distance関数を使用して、互いに指定された距離内にあるポイントをクエリします。

免責事項:これはドキュメントを読んだことに基づいています。私はこれを自分で試していません。

于 2009-12-02T13:19:35.670 に答える
0

lessthandot.com では、実際には 3 つの方法でこれを行うことができます。ブログを少しスクロールする必要がありますが、ブログはそこにあります。 http://blogs.lessthandot.com/

于 2009-04-30T20:58:47.583 に答える
0

ピタゴラスの定理を使用して、緯度/経度ポイントの 2 つのペアの近さを計算できます。

2 つの場所 (アルファ版とベータ版) がある場合、それらの距離を次のように計算できます。

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )
于 2009-05-01T09:50:13.547 に答える
0

次の URL のセットアップを使用して、以下のクエリを作成しました。(データベースのクエリに codeIgnitor を使用していることに注意してください)

http://howto-use-mysql-spatial-ext.blogspot.com/2007/11/using-circular-area-selection.html

function getRadius($point="POINT(-29.8368 30.9096)", $radius=2)
{
    $km = 0.009;
    $center = "GeomFromText('$point')";
    $radius = $radius*$km;
    $bbox = "CONCAT('POLYGON((',
        X($center) - $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) - $radius, '
    ))')";

    $query = $this->db->query("
    SELECT id, AsText(latLng) AS latLng, (SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )))/0.009 AS distance
    FROM crime_listing
    WHERE Intersects( latLng, GeomFromText($bbox) )
    AND SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )) < $radius
    ORDER BY distance
        ");

    if($query->num_rows()>0){
        return($query->result());
    }else{
        return false;
    }
}
于 2009-12-01T10:17:01.833 に答える