Haversine distance calculation between two points in Laravel

前端 未结 7 1538
迷失自我
迷失自我 2020-12-13 16:45

I\'m working on a laravel appliciation in which I need to find all the products that are within a certain radius of the user\'s coordinates. Products have a one to many rela

相关标签:
7条回答
  • 2020-12-13 16:55

    This was my implementation of it. I've chosen to alias my query out ahead of time, this way I can take advantage of Pagination. Furthermore, you need to explicitly select the columns that you wish to retrieve from the query. add them at the ->select(). Such as users.latitude, users.longitude, products.name, or whatever they may be.

    I have created a scope which looks something like this:

    public function scopeIsWithinMaxDistance($query, $location, $radius = 25) {
    
         $haversine = "(6371 * acos(cos(radians($location->latitude)) 
                         * cos(radians(model.latitude)) 
                         * cos(radians(model.longitude) 
                         - radians($location->longitude)) 
                         + sin(radians($location->latitude)) 
                         * sin(radians(model.latitude))))";
         return $query
            ->select() //pick the columns you want here.
            ->selectRaw("{$haversine} AS distance")
            ->whereRaw("{$haversine} < ?", [$radius]);
    }
    

    You can apply this scope to any model with a latitude andlongitude.

    Replace the $location->latitude with your latitude that you wish to search against, and replace the $location->longitude with the longitude that you wish to search against.

    Replace the model.latitude and model.longitude with the Models you wish to find around the $location based on the distance defined in the $radius.

    I know you have a functioning Haversine formula, but if you need to Paginate you can't use the code you've supplied.

    Hopefully this helps.

    0 讨论(0)
  • 2020-12-13 17:01

    Using Haversine method, you can calculate distance between two points using this function. It works but I don't know how to implement this in Laravel. Thought of sharing this anyway.

    $lat1 //latitude of first point
    $lon1 //longitude of first point 
    $lat2 //latitude of second point
    $lon2 //longitude of second point 
    $unit- unit- km or mile
    
    function point2point_distance($lat1, $lon1, $lat2, $lon2, $unit='K') 
        { 
            $theta = $lon1 - $lon2; 
            $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); 
            $dist = acos($dist); 
            $dist = rad2deg($dist); 
            $miles = $dist * 60 * 1.1515;
            $unit = strtoupper($unit);
    
            if ($unit == "K") 
            {
                return ($miles * 1.609344); 
            } 
            else if ($unit == "N") 
            {
            return ($miles * 0.8684);
            } 
            else 
            {
            return $miles;
          }
        }   
    
    0 讨论(0)
  • 2020-12-13 17:01

    I got a solution in Laravel.

        public function near($myLon, $myLat, $areaLon, $areaLat)
    {
        $this->applyCriteria();
        $this->applyScope();
    
        $results = $this->model->select(DB::raw("SQRT(
            POW(69.1 * (latitude - " . $myLat . "), 2) +
            POW(69.1 * (" . $myLon . " - longitude) * COS(latitude / 57.3), 2)) AS distance, SQRT(
            POW(69.1 * (latitude - " . $areaLat . "), 2) +
            POW(69.1 * (" . $areaLon . " - longitude) * COS(latitude / 57.3), 2)) AS area"), "YOUR_TABLE.*")->get();
    
        $this->resetModel();
        $this->resetScope();
    
        return $this->parserResult($results);
    }
    

    The answer is in Miles, you will have to replace YOUR_TABLE with the name of your database table. Thank you hope it helps

    0 讨论(0)
  • 2020-12-13 17:02

    If you are willing to use an external package instead, I suggest the infinitely useful PHPGeo library. I used it on a project that relied on these exact calculations, and it worked just fine. It saves you writing the calculations yourself from scratch and is tested to work.

    https://github.com/mjaschen/phpgeo

    Here is the documentation for Harvesine: https://phpgeo.marcusjaschen.de/#_distance_between_two_coordinates_haversine_formula

    0 讨论(0)
  • 2020-12-13 17:04

    This is a code I am using:

                $ownerLongitude = $request['longitude'];
                $ownerLatitude = $request['latitude'];
                $careType = 1;
                $distance = 3;
    
                $raw = DB::raw(' ( 6371 * acos( cos( radians(' . $ownerLatitude . ') ) * 
     cos( radians( latitude ) ) * cos( radians( longitude ) - radians(' . $ownerLongitude . ') ) + 
        sin( radians(' . $ownerLatitude . ') ) *
             sin( radians( latitude ) ) ) )  AS distance');
                $cares = DB::table('users')->select('*', $raw)
            ->addSelect($raw)->where('type', $careType)
            ->orderBy('distance', 'ASC')
            ->having('distance', '<=', $distance)->get();
    
    0 讨论(0)
  • 2020-12-13 17:08

    Create this function in your Model

     public static function getNearBy($lat, $lng, $distance,
                                                 $distanceIn = 'miles')
            {
                if ($distanceIn == 'km') {
                    $results = self::select(['*', DB::raw('( 0.621371 * 3959 * acos( cos( radians('.$lat.') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('.$lng.') ) + sin( radians('.$lat.') ) * sin( radians(lat) ) ) ) AS distance')])->havingRaw('distance < '.$distance)->get();
                } else {
                    $results = self::select(['*', DB::raw('( 3959 * acos( cos( radians('.$lat.') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('.$lng.') ) + sin( radians('.$lat.') ) * sin( radians(lat) ) ) ) AS distance')])->havingRaw('distance < '.$distance)->get();
                }
                return $results;
            }
    

    And you can use orderby, groupBy as per your requirement.

    0 讨论(0)
提交回复
热议问题