0

我的数据库有坐标条目。我想获取包含指定半径圆内坐标的条目。因此,我使用余弦球面定律。但是在所有数据库条目上检查这种情况的成本太高了。因此,我首先获取位于边界框中的坐标(此框包含上面指定的圆圈),然后spherical law of cosines在它们上应用 a 。

但问题是即使我有满足条件的条目,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

我发现了这个错误,下面是正确的查询。

$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 中使用,因为它是在 上执行的InitialResult,而不是userTrip.

于 2013-04-08T05:51:30.780 回答
0
$myUserId = $this->userId

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

$this->userId直接在查询中而不转义它。

于 2013-04-06T10:23:36.977 回答