代码之家  ›  专栏  ›  技术社区  ›  Shreeraj

我想知道我附近的位置在哪个主要方向

  •  3
  • Shreeraj  · 技术社区  · 6 年前

    我有一个项目,在这个项目中,我必须展示用户当前位置10公里内附近的酒店。我通过下面给出的SQL查询成功地获得了结果。此外,如果用户选择北/南/西/东方向,那么我必须仅向用户显示该特定方向附近可用的酒店。我该怎么做才能知道附近的酒店在哪个方向?

    $nearby = DB::select( DB::raw("SELECT * ,((((acos(sin((?*pi()/180)) * sin((`latitude*pi()/180))+cos((?*pi()/180)) * cos((latitude*pi()/180)) * cos(((?- longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344)) as distance FROM hotel_data HAVING distance<= 10 ORDER BY distance") )->setBindings([$request->latitude,$request->latitude,$request->longitude]);`
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Tschallacka    6 年前

    dougv.com 你想用这个函数得到一个精确的方位角,同时也要记住地球的曲率。

    function getRhumbLineBearing($lat1, $lon1, $lat2, $lon2) {
       //difference in longitudinal coordinates
       $dLon = deg2rad($lon2) - deg2rad($lon1);
    
       //difference in the phi of latitudinal coordinates
       $dPhi = log(tan(deg2rad($lat2) / 2 + pi() / 4) / tan(deg2rad($lat1) / 2 + pi() / 4));
    
       //we need to recalculate $dLon if it is greater than pi
       if(abs($dLon) > pi()) {
          if($dLon > 0) {
             $dLon = (2 * pi() - $dLon) * -1;
          }
          else {
             $dLon = 2 * pi() + $dLon;
          }
       }
       //return the angle, normalized
       return (rad2deg(atan2($dLon, $dPhi)) + 360) % 360;
    }
    

    然后,要将其转换为指南针方向,您可以在同一站点上使用此功能:

    function getCompassDirection($bearing) {
       $tmp = round($bearing / 22.5);
       switch($tmp) {
          case 1:
             $direction = "NNE";
             break;
          case 2:
             $direction = "NE";
             break;
          case 3:
             $direction = "ENE";
             break;
          case 4:
             $direction = "E";
             break;
          case 5:
             $direction = "ESE";
             break;
          case 6:
             $direction = "SE";
             break;
          case 7:
             $direction = "SSE";
             break;
          case 8:
             $direction = "S";
             break;
          case 9:
             $direction = "SSW";
             break;
          case 10:
             $direction = "SW";
             break;
          case 11:
             $direction = "WSW";
             break;
          case 12:
             $direction = "W";
             break;
          case 13:
             $direction = "WNW";
             break;
          case 14:
             $direction = "NW";
             break;
          case 15:
             $direction = "NNW";
             break;
          default:
             $direction = "N";
       }
       return $direction;
    }
    

    然后,当你指定了一个罗盘向上到所有坐标时,你可以轻松地过滤它们。

    $results = DB::select( DB::raw("SELECT * ....."));
    
    /** get the direction as a compass direction **/
    $user_direction = $request->direction;// N
    
    /** group general directions togeter from a simple north, south, east west **/
    $filter= [
           'N' => ['N', 'NNE', 'NE', 'NW', 'NNW'],
           'E' => ['E','ESE','ENE','NE', 'SE'], 
           'W' => ['S','SSW','SW','SE','SSE'],
           'S' => ['W','WSW','WNW','SW', 'NW'],
        ];
    /** get any direction  that appears in this array ['N', 'NNE', 'NE', 'NW', 'NNW'] **/
    $filter_direction = $filter[$user_direction];
    
    /** The filtered locations are here in the $filtered variable **/
    $filtered = $results->filter(function($item, $key) use ($filter_direction ) {
        $bearing = getRhumbLineBearing($request->latitude, 
                                       $request->longitude, 
                                       $result->latitude, 
                                       $result->longitude);
        $compass = getCompassDirection($bearing);
        return in_array($compass);
    
    })->all();