私のデータベースには座標のエントリがあります。指定された半径の円内にある座標を含むエントリを取得したいと考えています。したがって、余弦の球面法則を使用します。しかし、すべてのデータベース エントリでそのような状態をチェックするには、コストがかかりすぎます。したがって、最初に境界ボックス (このボックスは上で指定した円を囲んでいます) 内にある座標を取得し、それらに を適用spherical law of cosines
します。
しかし問題は、条件を満たしているエントリがある場合でも、MySQL が NULL を返すことです。上記の2つの条件を個別に確認したところ、動作することがわかりましたがspherical law of cosines
、他の条件(バウンディングボックス)を使用すると問題が発生します。
このリンクには、両方の条件に使用するコードがあります。
以下は私のコードです:
$R = 3959; // earth's mean radius in mile
// first-cut bounding box (in degrees)
$from_Lat = $userTrip->fromLat; // latitude of centre of bounding circle in degrees
$from_Lon = $userTrip->fromLon; // longitude of centre of bounding circle in degrees
$from_Rad = $userTripLength * 0.25; // radius of bounding circle in kilometers
$from_MaxLat = $from_Lat + rad2deg($from_Rad/$R);
$from_MinLat = $from_Lat - rad2deg($from_Rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$from_MaxLon = $from_Lon + rad2deg($from_Rad/$R/cos(deg2rad($from_Lat)));
$from_MinLon = $from_Lon - rad2deg($from_Rad/$R/cos(deg2rad($from_Lat)));
$to_Lat = $userTrip->toLat; // latitude of centre of bounding circle in degrees
$to_Lon = $userTrip->toLon; // longitude of centre of bounding circle in degrees
$to_Rad = $userTripLength * 0.50; // radius of bounding circle in kilometers
$to_MaxLat = $to_Lat + rad2deg($to_Rad/$R);
$to_MinLat = $to_Lat - rad2deg($to_Rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$to_MaxLon = $to_Lon + rad2deg($to_Rad/$R/cos(deg2rad($to_Lat)));
$to_MinLon = $to_Lon - rad2deg($to_Rad/$R/cos(deg2rad($to_Lat)));
$sql = "Select userTrip.id, userTrip.fromLat, userTrip.fromLon, userTrip.toLat, userTrip.toLon,
acos(sin(:from_lat)*sin(radians(userTrip.fromLat)) + cos(:from_lat)*cos(radians(userTrip.fromLat))*cos(radians(userTrip.fromLon) - :from_lon)) * :R AS SourceDistance,
acos(sin(:to_lat)*sin(radians(userTrip.toLat)) + cos(:to_lat)*cos(radians(userTrip.toLat))*cos(radians(userTrip.toLon) - :to_lon)) * :R AS DestinationDistance
From (
Select userTrip.id, userTrip.fromLat, userTrip.fromLon, userTrip.toLat, userTrip.toLon,
From userTrip
Where userTrip.userId != $this->userId
AND userTrip.departureTime > '".date('Y-m-d H:i:s')."'
AND userTrip.fromLat Between :from_minLat And :from_maxLat
AND userTrip.fromLon Between :from_minLon And :from_maxLon
AND userTrip.toLat Between :to_minLat And :to_maxLat
AND userTrip.toLon Between :to_minLon And :to_maxLon
)
Where acos(sin(:from_lat)*sin(radians(userTrip.fromLat)) + cos(:from_lat)*cos(radians(userTrip.fromLat))*cos(radians(userTrip.fromLon) - :from_lon)) * :R < :from_rad
AND acos(sin(:to_lat)*sin(radians(userTrip.toLat)) + cos(:to_lat)*cos(radians(userTrip.toLat))*cos(radians(userTrip.toLon) - :to_lon)) * :R < :to_rad";
$params = array(
'from_lat' => $from_Lat,
'from_lon' => $from_Lon,
'from_minLat' => $from_MinLat,
'from_minLon' => $from_MinLon,
'from_maxLat' => $from_MaxLat,
'from_maxLon' => $from_MaxLon,
'from_rad' => $from_Rad,
'to_lat' => $to_Lat,
'to_lon' => $to_Lon,
'to_minLat' => $to_MinLat,
'to_minLon' => $to_MinLon,
'to_maxLat' => $to_MaxLat,
'to_maxLon' => $to_MaxLon,
'to_rad' => $to_Rad,
'R' => $R
);
$stmt = $this->dbLink->prepare($sql);
try
{
$stmt->execute($params);
$matchCandidates = $stmt->fetchAll();
}
catch (PDOException $err)
{
echo $err->getMessage();
}
if ($matchCandidates == null)
throw new ErrorException("No match candidates found!");
これは常に「一致する候補が見つかりません!」というエラーを表示します。$params 配列では、最初は緯度と経度をラジアンに変換していましたが (それでも機能しませんでした)、多くのデバッグを行った後、それらは度数である必要があると思います。
前もって感謝します。