這次專題遇到了兩個經緯度之間的距離計算,目前有好幾間餐廳位置的資料,及很多活動場地位置資料,都有經緯度的資訊。而目的是要計算出選取某活動場地時,附近5公里內的餐廳有哪幾間,並且顯示彼此之間的距離是多少做成API。
上網查了一下公式,因為是計算球面兩點的最短距離,所以公式相當複雜,不過網路上有滿多別人已經寫好的演算公式的funcition可以參考,只要將兩地點的經緯度參數丟進去就可以了。
不過經過老師指點後,其實asp.net就有個參考可以計算經緯度兩點之間的最短距離。程式碼可以不用那麼長也不會讓使用者看到計算的公式。
那就是使用,也就是今天的主角 GeoCoordinate
System.Device
using System.Device.Location;
首先已知前端會post給我一個活動場地的經度(lng)及緯度(lat)給我。
先建立個post的function其名為PlaceNearRestaurant
[HttpPost]
public ActionResult PlaceNearRestaurant(double lat, double lng)
{
}
接下來在function內var一個new GeoCoordinate資料型別。
var coord = new GeoCoordinate(lat, lng);
GeoCoordinate是經緯度的資料型別,要提供緯度及經度,需引用System.Device.Location才可呼叫的出來。
緯度的範圍可從-90.0 到90.0,若不在這範圍內則會報錯。
private Activivtiest db = new Activivtiest();
Activivtiest是ADO.NET的實體資料模型,是與資料庫做連接的一個model。
var foods = db.Restaurants.Where(x => !(string.IsNullOrEmpty(x.Latitude)) || !(string.IsNullOrEmpty(x.Longitude))).ToList();
function內從資料庫取出全部的餐廳資料(Restaurants資料表),但這邊要先使用where過濾掉沒有提供經度及緯度的餐廳資料,不然到時候若某餐廳沒有提供經緯度,GeoCoordinate計算時會報錯。
var Newfoods = foods.Select(x => new
{
Id = x.Id,
Name = x.Name,
lat = x.Latitude,
lng = x.Longitude,
add = x.Address,
optime = x.Time,
tel = x.TEL
}
return Content(JsonConvert.SerializeObject(Newfoods), "application/json");
再var一個Newfood來對剛剛的foods進行篩選顯示,先測試一下是否有取得餐廳的資料,回傳的是Json的格式。
確認有取得資料後,就要來計算活動場地與餐廳之間的距離了。
Dis = (int)(new GeoCoordinate(double.Parse(x.Latitude),double.Parse(x.Longitude))).GetDistanceTo(coord)
在上面Newfoods的Select內需要再多加一個Dis欄位,用來存放計算後的距離資料,資料型態使用int。
是使用 GeoCoordinate().GetDistanceTo()
這個方法是GeoCoordinate內建的計算球面兩點的最短距離方法,演算法都已經寫在GetDistanceTo()內了,只需要丟入需要的參數即可。回傳的距離單位是公尺(M)。
用法:
GeoCoordinate(餐廳的緯度,餐廳的經度).GetDistanceTo(活動場地的經緯度)
記得若從資料庫取得座標記得要將資料型態轉型為double。
回傳後,就可以成功的獲得計算餐廳與活動場地的距離了。
程式碼:
return Content(JsonConvert.SerializeObject(Newfoods.Where(x => x.Dis <= 5000).OrderBy(x => x.Dis)), "application/json");
只要在Newfoods內進行where資料篩選,取得剛剛的Dis欄位,然後只顯示小於等於5000公尺的資料就好,並使用遞增的方式呈現。
序列化成Json格式,就可以取得5公里內的餐廳資料了。
程式碼:
DisView = (int)(new GeoCoordinate(double.Parse(x.Latitude),double.Parse(x.Longitude))).GetDistanceTo(coord) >= 1000
? ((double)(new GeoCoordinate(double.Parse(x.Latitude),double.Parse(x.Longitude))).GetDistanceTo(coord) / 1000.0).ToString("0.0") + "KM"
: (int)(newDisView GeoCoordinate(double.Parse(x.Latitude),double.Parse(x.Longitude))).GetDistanceTo(coord) + "M"
看起來有點複雜,就是在Newfoods建立一個用來顯示距離的欄位[DisView],使用三元運算式,將計算距離的公式套入,若大於等於1000公尺則取計算後的距離/1000(將單位轉換成公里),再加上字串KM。
不然的話小於1000就顯示計算後的距離就好,單位就不用轉換成公里了,並加上字串M。
就可以return資料了,這樣就完成了一個可以計算活動場地與餐廳的經緯度距離並篩選出5公里內的餐廳API了。
using
using twActivitiest.Models;
using System.Device.Location;
using Newtonsoft.Json;
function
//與資料庫的關聯
private Activivtiest db = new Activivtiest();
#region 顯示場地5公里內的美食與顯示距離
[HttpPost]
public ActionResult PlaceNearRestaurant(double lat, double lng)
{
//取得post的經緯度資料並存成座標型態
var coord = new GeoCoordinate(lat, lng);
//從資料庫進行篩選,不要經度或緯度有空白資料的餐廳
var foods = db.Restaurants.Where(x => !(string.IsNullOrEmpty(x.Latitude)) || !(string.IsNullOrEmpty(x.Longitude))).ToList();
//篩選要的欄位並計算活動場地與餐廳之間的距離
var Newfoods = foods.Select(x => new
{
Id = x.Id,
Name = x.Name,
lat = x.Latitude,
lng = x.Longitude,
add = x.Address,
optime = x.Time,
tel = x.TEL,
//計算活動場地與餐廳的距離方法
Dis = (int)(new GeoCoordinate(double.Parse(x.Latitude), double.Parse(x.Longitude))).GetDistanceTo(coord),
//距離顯示方式大於等於1000公尺就將單位轉成公里
DisView = (int)(new GeoCoordinate(double.Parse(x.Latitude), double.Parse(x.Longitude))).GetDistanceTo(coord) >= 1000
? ((double)(new GeoCoordinate(double.Parse(x.Latitude), double.Parse(x.Longitude))).GetDistanceTo(coord) / 1000.0).ToString("0.0") + "KM"
: (int)(new GeoCoordinate(double.Parse(x.Latitude), double.Parse(x.Longitude))).GetDistanceTo(coord) + "M"
}
);
//篩選出只要取得5000公尺內的餐廳資料,並將資料型態序列化成Json格式,並回傳資料
return Content(JsonConvert.SerializeObject(Newfoods.Where(x => x.Dis <= 5000).OrderBy(x => x.Dis)), "application/json");
}
#endregion
以上,感謝閱讀。
感謝分享~
不過最後一段,您其實可以直接Return Json就好~XDDD
e.g.
return Json(Newfoods.Where(x => x.Dis <= 5000).OrderBy(x => x.Dis));
原來可以醬,感謝Y大><
後來發現若直接用return Json()方式回傳的話,datetime會自動變成date(xxxxxxxx)的格式。
使用Content(JsonConvert.SerializeObject()的方式,datetime的格式就是資料長怎樣就是怎樣。