0

私のデータベースには座標のエントリがあります。指定された半径の円内にある座標を含むエントリを取得したいと考えています。したがって、余弦の球面法則を使用します。しかし、すべてのデータベース エントリでそのような状態をチェックするには、コストがかかりすぎます。したがって、最初に境界ボックス (このボックスは上で指定した円を囲んでいます) 内にある座標を取得し、それらに を適用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 配列では、最初は緯度と経度をラジアンに変換していましたが (それでも機能しませんでした)、多くのデバッグを行った後、それらは度数である必要があると思います。

前もって感謝します。

4

2 に答える 2

0
$myUserId = $this->userId

Select ...
Where userTrip.userId != $myUserId

エスケープせずにクエリに$this->userId直接入力します。

于 2013-04-06T10:23:36.977 に答える
0

私はバグを見つけました。以下は正しいクエリです。

$sql = "Select id,fromLat,fromLon,toLat,toLon,
    acos(sin(:from_lat)*sin(radians(fromLat)) + cos(:from_lat)*cos(radians(fromLat))*cos(radians(fromLon) - :from_lon)) * :R AS SourceDistance,
    acos(sin(:to_lat)*sin(radians(toLat)) + cos(:to_lat)*cos(radians(toLat))*cos(radians(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
        ) AS InitialResult
      Where acos(sin(:from_lat)*sin(radians(fromLat)) + cos(:from_lat)*cos(radians(fromLat))*cos(radians(fromLon) - :from_lon)) * :R < :from_rad
      AND acos(sin(:to_lat)*sin(radians(toLat)) + cos(:to_lat)*cos(radians(toLat))*cos(radians(toLon) - :to_lon)) * :R < :to_rad";

1) 内部 SELECT クエリの結果にエイリアスを指定する必要があります。Initialresultこの場合。
2) ではなくuserTrip.で実行されるため、外側の SELECTでは使用できませInitialResultuserTrip

于 2013-04-08T05:51:30.780 に答える