在o2o項目中,常常要用到在用戶下單時判斷用戶所填地址的座標點是否在服務範圍內的狀況,這裏參考網上的實現方式,用C#來實現,經測試後有效,特此記錄。html
public class MapHelper { /// <summary> /// 判斷一個座標點在多邊形座標點的內部仍是外部 /// </summary> /// <param name="point">要判斷的座標點</param> /// <param name="pts">多邊形座標點集合</param> /// <returns></returns> public static bool IsPointInPolygon(Point point, List<Point> pts) { int N = pts.Count; //若是點位於多邊形的頂點或邊上,也算作點在多邊形內,直接返回true bool boundOrVertex = true; //通過點的次數 int intersectCount = 0; double precision = 2e-10; Point p1, p2; Point p = point;//當前點 p1 = pts[0]; for (int i = 1; i <= N; i++) { //若是點在多邊形上 if (p.Equals(p1)) { return boundOrVertex; } p2 = pts[(i % N)]; if (p.Lng<Math.Min(p1.Lng,p2.Lng)||p.Lng>Math.Max(p1.Lng,p2.Lng)) { p1 = p2; continue; } if (p.Lng>Math.Min(p1.Lng,p2.Lng)&&p.Lng<Math.Max(p1.Lng,p2.Lng)) { if (p.Lat<=Math.Max(p1.Lat,p2.Lat)) { if (p1.Lng==p2.Lng&&p.Lat>=Math.Min(p1.Lat,p2.Lat)) { return boundOrVertex; } if (p1.Lat==p2.Lat) { if (p1.Lat==p.Lat) { return boundOrVertex; } else { intersectCount++; } } else { double xinters = (p.Lng - p1.Lng) * (p2.Lat - p1.Lat) / (p2.Lng - p1.Lng) + p1.Lat; if (Math.Abs(p.Lat-xinters)<precision) { return boundOrVertex; } if (p.Lat<xinters) { intersectCount++; } } } } else { if (p.Lng==p2.Lng&&p.Lat<=p2.Lat) { Point p3 = pts[(i+1)%N]; if (p.Lng>=Math.Min(p1.Lng,p3.Lng)&&p.Lng<=Math.Max(p1.Lng,p3.Lng)) { intersectCount++; } else { intersectCount += 2; } } } p1 = p2; } if (intersectCount%2==0) { //偶數在多邊形外 return false; } else { //奇數在多邊形內 return true; } } } public class Point { /// <summary> /// 經度 /// </summary> public double Lng { get; set; } /// <summary> /// 緯度 /// </summary> public double Lat { get; set; } }
這裏我用高德地圖標出了北京五環範圍的座標點集合,而後隨意選擇一個座標點來進行判斷:工具
座標點能夠用這個工具來獲取:高德地圖API測試
五環範圍:code
隨機座標:htm
class Program { static void Main(string[] args) { var Plist = new List<Point> { new Point {Lng=116.222208,Lat= 39.992436}, new Point {Lng=116.327147,Lat= 40.02046}, new Point {Lng=116.353948,Lat= 40.02299}, new Point {Lng=116.44128,Lat= 40.020526}, new Point {Lng=116.48441,Lat=40.013624 }, new Point {Lng=116.541101,Lat= 39.942393}, new Point {Lng=116.549202,Lat= 39.851595}, new Point {Lng=116.43082,Lat=39.785968}, new Point {Lng=116.296044,Lat=39.777442 }, new Point {Lng=116.225062,Lat=39.845517 }, new Point {Lng=116.211308,Lat= 39.894396}, new Point {Lng=116.212595,Lat=39.944705} }; //var p = new Point { Lng = 116.37297, Lat = 40.021857 }; //林萃橋地鐵站 內 //var p = new Point { Lng = 116.47086, Lat = 39.99648 }; //望京西園四區 內 //var p = new Point { Lng = 116.533811, Lat = 39.880533 }; //觀音禪寺 內 //var p = new Point { Lng = 116.299713, Lat = 39.772619 }; //俏狐國際 外 //var p = new Point { Lng = 116.416336, Lat = 39.78394 }; //芳園裏小區 外 var p = new Point { Lng = 116.429039, Lat = 39.790535 }; //潤楓錦尚小區 內 bool isin = MapHelper.IsPointInPolygon(p, Plist); if (isin) { Console.WriteLine("隨機點在五環範圍內,能夠派單"); } else { Console.WriteLine("隨機點不在五環範圍內"); } Console.ReadKey(); } }