2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Laravel] 緯度経度情報から距離順にソートする

Last updated at Posted at 2020-12-03

環境

Laravel 7.x
MySQL 8

やりたいこと

緯度経度情報から店舗を近い順に並べ替えたい
精度は10mくらいでいい

データ

DB の shops テーブルに緯度 latitude, 経度 longitude カラムがある

id name latitude longitude
1 店舗A 35.1111 137.1111
2 店舗B 35.2222 137.2222
3 店舗C 35.3333 137.3333
4 店舗D 35.4444 137.4444
... ... ... ...

緯度経度から距離を出す計算式

地点P(緯度φ1,経度λ1) から 地点Q(緯度φ2,経度λ2)までの距離を x [km] とすると

x = \arccos(\cos\phi_1\cos\phi_2\cos(\lambda_1-\lambda_2) + \sin\phi_1\sin\phi_2) \times 6370

出典: http://www.orsj.or.jp/archive2/or60-12/or60_12_701.pdf

6370は地球の半径[km]。

OrderByRawを使う

上記計算式を orderByRaw を使って実装する。
ソートするだけなので、定数である半径 6370 はいらない。

$latitude  = $request->get('latitude');  // 起点の緯度 queryに入っているテイ
$longitude = $request->get('longitude'); // 起点の経度 queryに入っているテイ
$shops = \App\Models\Shop::orderByRaw(
    'ACOS(COS(RADIANS('.$latitude.')) * COS(RADIANS(latitude)) * COS(RADIANS(longitude) - RADIANS('.$longitude.')) 
    + SIN(RADIANS('.$latitude.')) * SIN(RADIANS(latitude)))'
  )
  ->get();

距離を値として取りたい場合

上記だとソートするだけになるが、距離も値として欲しいときはこちら。

$latitude  = $request->get('latitude');  // 起点の緯度 queryに入っているテイ
$longitude = $request->get('longitude'); // 起点の経度 queryに入っているテイ
$shops = \App\Models\Shop::select('*', 
  DB::raw('6370 * ACOS(COS(RADIANS('.$latitude.')) * COS(RADIANS(latitude)) * COS(RADIANS(longitude) - RADIANS('.$longitude.')) 
    + SIN(RADIANS('.$latitude.')) * SIN(RADIANS(latitude))) as distance'))
  ->orderBy('distance')
  ->get();
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?