C# 计算地图上某个坐标点的是否在多边形内

 新葡亰编程     |      2020-01-16

判断是否在多边形内,原理是画条射线,看射线与多边形相交的点是奇数还是偶数,看本代码是我从网上抄的,并没有使用和检查过,原文见:。

项目中用到的经纬度方位计算方法:

public class location { public double lat; public double lng; } public class GpsPolygonHelper { /// <summary> /// 坐标点是否在多边形内判断 /// </summary> /// <param name="point"></param> /// <param name="pts"></param> /// <returns></returns> public static bool isPointInPolygon(location point, List<location> pts) { //检查类型 if (point == null || pts == null) return false; var N = pts.Count; var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true var intersectCount = 0; //cross points count of x var precision = 2e-10; //浮点类型计算时候与0比较时候的容差 location p1, p2; //neighbour bound vertices var p = point; //测试点 p1 = pts[0]; //left vertex for (var i = 1; i <= N; ++i) { //check all rays if (p.lat.Equals(p1.lat) && p.lng.Equals(p1.lng)) { return boundOrVertex; //p is an vertex } p2 = pts[i % N]; //right vertex if (p.lat < Math.Min(p1.lat, p2.lat) || p.lat > Math.Max(p1.lat, p2.lat)) { //ray is outside of our interests p1 = p2; continue; //next ray left point } if (p.lat > Math.Min(p1.lat, p2.lat) && p.lat < Math.Max(p1.lat, p2.lat)) { //ray is crossing over by the algorithm (common part of) if (p.lng <= Math.Max(p1.lng, p2.lng)) { //x is before of ray if (p1.lat == p2.lat && p.lng >= Math.Min(p1.lng, p2.lng)) { //overlies on a horizontal ray return boundOrVertex; } if (p1.lng == p2.lng) { //ray is vertical if (p1.lng == p.lng) { //overlies on a vertical ray return boundOrVertex; } else { //before ray ++intersectCount; } } else { //cross point on the left side var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat

2点经纬度计算方位,先计算二者的方位角度:该方法得出方位是点A相对于B的逆时针方向

  • p1.lat) + p1.lng; //cross point of lng if (Math.Abs(p.lng - xinters) < precision) { //overlies on a ray return boundOrVertex; } if (p.lng < xinters) { //before ray ++intersectCount; } } } } else { //special case when ray is crossing through the vertex if (p.lat == p2.lat && p.lng <= p2.lng) { //p crossing over p2 var p3 = pts[(i + 1) % N]; //next vertex if (p.lat >= Math.Min(p1.lat, p3.lat) && p.lat <= Math.Max(p1.lat, p3.lat)) { //p.lat lies between p1.lat & p3.lat ++intersectCount; } else { intersectCount += 2; } } } p1 = p2; //next ray left point } if (intersectCount % 2 == 0) { //偶数在多边形外 return false; } else { //奇数在多边形内 return true; } }

    /// <summary>
        /// 根据经纬度计算角度
        /// </summary>
        /// <param name="lat1"></param>
        /// <param name="lng1"></param>
        /// <param name="lat2"></param>
        /// <param name="lng2"></param>
        /// <returns></returns>
       
        public static double GetJiaoDu(double lat1, double lng1, double lat2, double lng2)
        {
            double x1 = lng1;
            double y1 = lat1;
            double x2 = lng2;
            double y2 = lat2;
            double pi = Math.PI;
            double w1 = y1 / 180 * pi;
            double j1 = x1 / 180 * pi;
            double w2 = y2 / 180 * pi;
            double j2 = x2 / 180 * pi;
            double ret;
            if (j1 == j2)
            {
                if (w1 > w2) return 270; //北半球的情况,南半球忽略
                else if (w1 < w2) return 90;
                else return -1;//位置完全相同
            }
            ret = 4 * Math.Pow(Math.Sin((w1 - w2) / 2), 2) - Math.Pow(Math.Sin((j1 - j2) / 2) * (Math.Cos(w1) - Math.Cos(w2)), 2);
            ret = Math.Sqrt(ret);
            double temp = (Math.Sin(Math.Abs(j1 - j2) / 2) * (Math.Cos(w1) + Math.Cos(w2)));
            ret = ret / temp;
            ret = Math.Atan(ret) / pi * 180;
            if (j1 > j2) // 1为参考点坐标
            {
                if (w1 > w2) ret += 180;
                else ret = 180 - ret;
            }
            else if (w1 > w2) ret = 360 - ret;
            return ret;
        }