Created
September 29, 2015 20:06
-
-
Save bbatsche/35e7f3e0b127f9fab653 to your computer and use it in GitHub Desktop.
Haversine Query Scope
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class BaseModel { | |
const UNIT_KM = 111.045; | |
const UNIT_MI = 69.0; | |
// Throw this function in any model with latitude/longitude columns | |
// Or if multiple models have those values you can put it in your BaseModel | |
public function scopeNearLatLong($query, $lat, $lng, $radius = 10, $unit = 69.0) | |
{ | |
if (!is_numeric($lat) || -90 >= $lat || $lat >= 90) { | |
throw new RangeException("Latitude must be between -90 and 90 degrees."); | |
} | |
if (!is_numeric($lng) || -180 >= $lng || $lng >= 180) { | |
throw new RangeException("Longitude must be between -180 and 180 degrees."); | |
} | |
$subQuery = clone $query; | |
$latDistance = $radius / $unit; | |
$latNorth = $lat - $latDistance; | |
$latSouth = $lat + $latDistance; | |
$lngDistance = $radius / ($unit * cos(deg2rad($lat))); | |
$lngEast = $lng - $lngDistance; | |
$lngWest = $lng + $lngDistance; | |
$subQuery->selectRaw(DB::raw('*, (? * DEGREES( | |
ACOS( | |
COS(RADIANS(?)) * COS(RADIANS(latitude)) * COS(RADIANS(? - longitude)) | |
+ SIN(RADIANS(?)) * SIN(RADIANS(latitude)) | |
) | |
)) AS distance'))->addBinding([$unit, $lat, $lng, $lat], 'select'); | |
$subQuery->whereBetween('latitude', [$latNorth, $latSouth]); | |
$subQuery->whereBetween('longitude', [$lngEast, $lngWest]); | |
$query->from(DB::raw('(' . $subQuery->toSql() . ') as d')); | |
$query->mergeBindings($subQuery->getQuery()); | |
$query->where('distance', '<=', $radius); | |
} | |
} | |
// To use: | |
$latitude = 29.4284595; | |
$longitude = -98.492433; | |
// Default radius is 10; default unit is miles. | |
Model::nearLatLong($latitude, $longitude)->get(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment