2

地理座標と場所に関するその他の情報を含むテーブルが MySQL データベースにあります。表の各行は地理的な場所を表し、緯度 = 45.05235 および経度 = 8.02354 のような座標を持ちます。これはヨーロッパのどこかの場所です。

いくつかの入力地理座標 (同じ形式) を指定すると、そのテーブルから最も近い場所、または半径内の最も近い場所を選択する必要があります。

すでにインデックスを使用していますが、これらの関数は何度も使用されるため、プロセスを高速化したいと考えています。

1 つのクエリで、最も近い場所または特定の半径内の場所を直接選択できれば役立つかもしれません。もちろん、他のソリューションも大歓迎です。

最も近い場所を取得する関数を作成しました(これは機能していますが遅いです):

<?php
//Function for getting nearest destinations:
function nearest_destination($lat1,$lon1,$radius,$type,$maxdistance){
  //Determine geo bounds:
  $lonlow = $lon1 - rad2deg($maxdistance/6371);
  $lonhigh = $lon1 + rad2deg($maxdistance/6371);
  $latlow = $lat1 - rad2deg($maxdistance/6371);
  $lathigh = $lat1 + rad2deg($maxdistance/6371);
  
  //Database details and connect to database
  include(realpath($_SERVER["DOCUMENT_ROOT"]).'/connect_to_db.php'); 
  //Set initial counters to zero
  $ii=0;
  $i=0;
  
  while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
    $shortnamelist[$ii]=$row['shortname'];
    $fullnamelist[$ii]=$row['fullname'];
    $latitudelist[$ii]=$row['latitude'];
    $longitudelist[$ii]=$row['longitude'];
    $lon2=$row['longitude'];
    $lat2=$row['latitude'];
    
    //Calculate the distance:
    $delta_lon = $lon2 - $lon1;
    $earth_radius = "6371"; # in km
    $distance  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon)) ;
    $distance  = acos($distance);
    $distance  = $earth_radius*$distance;
    $distance  = round($distance, 4);
    $distancelist[$ii] = $distance;
    $ii=$ii+1;
  }
  
  //Select position of nearest, and select the destination
  if(isset($distancelist)){
    $minkey=array_keys($distancelist, min($distancelist));
    $minkey=$minkey[0];
    
    $fullname=$fullnamelist[$minkey];
    $shortname=$shortnamelist[$minkey];
    $latitude=$latitudelist[$minkey];
    $longitude=$longitudelist[$minkey];
    
    // remove the big arrays to conserve memory:
    unset($fullnamelist);
    unset($latitudelist);
    unset($longitudelist);
    unset($distancelist);
    unset($shortnamelist);
  }
  
  if(isset($destinid)=='TRUE'){
    $nearest_destination = array("shortname" => $shortname, "fullname" => $fullname, "latitude" => $latitude, "longitude" => $longitude, "distancelist" => $distancelisting);}
  else $nearest_destination = 0;
  mysql_close ();
  return $nearest_destination;
}
?>

これは、特定の半径内の最も近い場所を選択する関数です (動作しますが遅い):

<?php
//Function for getting nearest destinations:
function nearest_destination($lat1,$lon1,$radius,$type,$maxdistance){
  //Determine geo bounds:
  $lonlow = $lon1 - rad2deg($maxdistance/6371);
  $lonhigh = $lon1 + rad2deg($maxdistance/6371);
  $latlow = $lat1 - rad2deg($maxdistance/6371);
  $lathigh = $lat1 + rad2deg($maxdistance/6371);
  
  // Convert from string to number:
  $lon1=floatval($lon1);
  $lat1=floatval($lat1);
  
  //Database details and connect to database
  include(realpath($_SERVER["DOCUMENT_ROOT"]).'/connect_to_database.php'); //Get DB login details
  
  //Select data from destinations table:
  $sql="SELECT shortname, fullname, latitude, longitude FROM destinations WHERE type='$type' AND longitude > $lonlow AND longitude < $lonhigh AND latitude > $latlow AND latitude < $lathigh";
  $result=mysql_query($sql);
  
  //Set initial counter to zero
  $i=0;
  
  while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
    $lon2=$row['longitude'];
    $lat2=$row['latitude'];
    $lon2=floatval($lon2);
    $lat2=floatval($lat2);
    
    //Calculate the distance:
    $delta_lon = $lon2 - $lon1;
    $earth_radius = "6371"; # in km
    $distance  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon)) ;
    $distance  = acos($distance);
    $distance  = $earth_radius*$distance;
    $distance  = round($distance, 4);
    
    //If distance is smaller than the radius the destination is saved in the array:
    if($distance<$radius){
      $fullname[$i]=$row['fullname'];
      $shortname[$i]=$row['shortname'];
      $latitude[$i]=$row['latitude'];
      $longitude[$i]=$row['longitude'];
      $distancelisting[$i] = $distance;
      $i=$i+1;
    }
  }
  
  if(isset($destinid)=='TRUE'){
    $nearest_destination = array("shortname" => $shortname, "fullname" => $fullname, "latitude" => $latitude, "longitude" => $longitude, "distancelist" => $distancelisting);
  }else $nearest_destination = 0;
  mysql_close ();
  return $nearest_destination;
}
?>
4

2 に答える 2

1

mysql gisサポートを使用すると、このために作成された速度が向上します。距離を常に読んで比較している場合は、完全にサポートされている地理空間データベースであるpostgisを使用する価値があります。これにより、効率的な距離クエリのためにポイントにインデックスを付けることができます。MySQLは限定的なサポートを提供し、GEOShttp ://trac.osgeo.org/geos/に依存しています

http://forge.mysql.com/wiki/GIS_Functions

http://postgis.refractions.net/

これに最も関連するリンクは、Anigelによるコメントによって投稿されました。これは、あなたの質問に対する正確な答えを提供します。2つの緯度/経度間の距離を見つける最速の方法

于 2012-05-03T13:21:59.667 に答える
1

必要に応じて自由に変更してください。

<?php
$center_lat = $_GET["lat"];
$center_lng = $_GET["lng"];
$radius = $_GET["radius"];
$unit = $_GET["unit"];
$unitConst = $unit == "mi" ? 3959 : 6371;
$sql = sprintf("SELECT Address, City, State, Country, PostalCode, PhoneNumber, Lat, Lng, ($unitConst * acos(cos(radians('%s')) * cos(radians(Lat)) * cos(radians(Lng) - radians('%s')) + sin(radians('%s')) * sin(radians(Lat)))) AS Distance FROM destinations WHERE (Lat != '0' AND Lng !=0) HAVING distance < '%s' ORDER BY distance", mysql_real_escape_string($center_lat), mysql_real_escape_string($center_lng), mysql_real_escape_string($center_lat), mysql_real_escape_string($radius));
?>
于 2012-05-03T13:25:17.547 に答える